From ee84d374356b3332e68258e49a87a2ec64ec0745 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 29 Mar 2025 20:48:47 +0700 Subject: [PATCH 001/504] Use SpringCacheBasedTicketCache Signed-off-by: Tran Ngoc Nhan --- docs/modules/ROOT/pages/servlet/authentication/cas.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/servlet/authentication/cas.adoc b/docs/modules/ROOT/pages/servlet/authentication/cas.adoc index 59125bde84..115c43d756 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/cas.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/cas.adoc @@ -448,7 +448,7 @@ You can find an example of the updates required to accept all proxies below. - + From 4703f9cf1ce7891486ba62f38a28c79aa4021276 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 31 Mar 2025 14:06:45 -0600 Subject: [PATCH 002/504] Update format + check command Issue gh-14575 --- CONTRIBUTING.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 4f4d2a2d00..e0706cea23 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -79,7 +79,7 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize. -To format the code as well as check the style, run `./gradlew format check`. +To format the code as well as check the style, run `./gradlew format && ./gradlew check`. [[submit-a-pull-request]] === Submit a Pull Request @@ -104,7 +104,7 @@ If this is for an issue, consider a branch name with the issue number, like `gh- 6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year. 7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds 8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`. -9. [[format-code]] For each commit, build the code using `./gradlew format check`. +9. [[format-code]] For each commit, build the code using `./gradlew format && ./gradlew check`. This command ensures the code meets most of <>; a notable exception is import order. 10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent multiple edits or corrections of the same logical change. From 9a897d0b62ceed60d38f367ebc79753cae04b81d Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 28 Mar 2025 13:10:35 +0300 Subject: [PATCH 003/504] Add Support Postgres To JdbcUserCredentialRepository Closes gh-16832 Signed-off-by: Max Batischev --- .../aot/hint/UserCredentialRuntimeHints.java | 6 ++++-- .../user-credentials-schema-postgres.sql | 18 ++++++++++++++++++ .../hint/UserCredentialRuntimeHintsTests.java | 5 +++-- 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 web/src/main/resources/org/springframework/security/user-credentials-schema-postgres.sql diff --git a/web/src/main/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHints.java b/web/src/main/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHints.java index c3b4c95a14..9670056872 100644 --- a/web/src/main/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHints.java +++ b/web/src/main/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,9 @@ class UserCredentialRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - hints.resources().registerPattern("org/springframework/security/user-credentials-schema.sql"); + hints.resources() + .registerPattern("org/springframework/security/user-credentials-schema.sql") + .registerPattern("org/springframework/security/user-credentials-schema-postgres.sql"); } } diff --git a/web/src/main/resources/org/springframework/security/user-credentials-schema-postgres.sql b/web/src/main/resources/org/springframework/security/user-credentials-schema-postgres.sql new file mode 100644 index 0000000000..fb93b3869a --- /dev/null +++ b/web/src/main/resources/org/springframework/security/user-credentials-schema-postgres.sql @@ -0,0 +1,18 @@ +create table user_credentials +( + credential_id varchar(1000) not null, + user_entity_user_id varchar(1000) not null, + public_key bytea not null, + signature_count bigint, + uv_initialized boolean, + backup_eligible boolean not null, + authenticator_transports varchar(1000), + public_key_credential_type varchar(100), + backup_state boolean not null, + attestation_object bytea, + attestation_client_data_json bytea, + created timestamp, + last_used timestamp, + label varchar(1000) not null, + primary key (credential_id) +); diff --git a/web/src/test/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHintsTests.java b/web/src/test/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHintsTests.java index 33799cc6f9..ed44b4cb26 100644 --- a/web/src/test/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHintsTests.java +++ b/web/src/test/java/org/springframework/security/web/aot/hint/UserCredentialRuntimeHintsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,7 +53,8 @@ public class UserCredentialRuntimeHintsTests { } private static Stream getClientRecordsSqlFiles() { - return Stream.of("org/springframework/security/user-credentials-schema.sql"); + return Stream.of("org/springframework/security/user-credentials-schema.sql", + "org/springframework/security/user-credentials-schema-postgres.sql"); } } From 857ef6fe087f3e2adb6e7f8c2b6de9817575078c Mon Sep 17 00:00:00 2001 From: DingHao Date: Wed, 26 Mar 2025 08:53:33 +0800 Subject: [PATCH 004/504] WithHttpOnlyCookie defaults to false Closes gh-16820 Signed-off-by: DingHao --- .../csrf/CookieServerCsrfTokenRepository.java | 4 ++-- .../CookieServerCsrfTokenRepositoryTests.java | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java index 40301e5de7..37659f8133 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,7 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep */ public static CookieServerCsrfTokenRepository withHttpOnlyFalse() { CookieServerCsrfTokenRepository result = new CookieServerCsrfTokenRepository(); - result.setCookieCustomizer((cookie) -> cookie.httpOnly(false)); + result.cookieHttpOnly = false; return result; } diff --git a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java index 1aa89f21a8..a6c290fd88 100644 --- a/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -290,6 +290,21 @@ class CookieServerCsrfTokenRepositoryTests { loadAndAssertExpectedValues(); } + // gh-16820 + @Test + void withHttpOnlyFalseWhenCookieCustomizerThenStillDefaultsToFalse() { + CookieServerCsrfTokenRepository repository = CookieServerCsrfTokenRepository.withHttpOnlyFalse(); + repository.setCookieCustomizer((customizer) -> customizer.maxAge(1000)); + MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/dummy"); + MockServerWebExchange exchange = MockServerWebExchange.from(request); + CsrfToken csrfToken = repository.generateToken(exchange).block(); + repository.saveToken(exchange, csrfToken).block(); + ResponseCookie cookie = exchange.getResponse().getCookies().getFirst("XSRF-TOKEN"); + assertThat(cookie).isNotNull(); + assertThat(cookie.getMaxAge().getSeconds()).isEqualTo(1000); + assertThat(cookie.isHttpOnly()).isEqualTo(Boolean.FALSE); + } + private void setExpectedHeaderName(String expectedHeaderName) { this.csrfTokenRepository.setHeaderName(expectedHeaderName); this.expectedHeaderName = expectedHeaderName; From 2a24bb0b2637b792b18faf5d2c77363f7a147c8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 03:42:37 +0000 Subject: [PATCH 005/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.28.6.RELEASE to 0.29.0.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.28.6.RELEASE...0.29.0.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e7bff368c..3c8b5eccd4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.28.6.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.0.RELEASE' [plugins] From 2885b0f75f6ba42693e0f2eab0c2f267722d9e42 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 2 Apr 2025 11:16:26 -0600 Subject: [PATCH 006/504] Add valueOf This commit adds a static factory for returning a constant ClientAuthenticationMethod or creating a new one when there is no match. Issue gh-16825 --- ...ientRegistrationsBeanDefinitionParser.java | 4 +-- .../core/ClientAuthenticationMethod.java | 26 +++++++++++++++++- .../core/ClientAuthenticationMethodTests.java | 27 ++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java index 80ff475579..c908958f30 100644 --- a/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,7 +125,7 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_SECRET)) .ifPresent(builder::clientSecret); getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD)) - .map(ClientAuthenticationMethod::new) + .map(ClientAuthenticationMethod::valueOf) .ifPresent(builder::clientAuthenticationMethod); getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE)) .map(AuthorizationGrantType::new) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java index 5dbf88cd85..1e2e2c1ebc 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.security.oauth2.core; import java.io.Serializable; +import org.springframework.lang.NonNull; import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.util.Assert; @@ -92,6 +93,29 @@ public final class ClientAuthenticationMethod implements Serializable { return this.value; } + static ClientAuthenticationMethod[] methods() { + return new ClientAuthenticationMethod[] { CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, + PRIVATE_KEY_JWT, NONE, TLS_CLIENT_AUTH, SELF_SIGNED_TLS_CLIENT_AUTH }; + } + + /** + * A factory to construct a {@link ClientAuthenticationMethod} based on a string, + * returning any constant value that matches. + * @param method the client authentication method + * @return a {@link ClientAuthenticationMethod}; specifically the corresponding + * constant, if any + * @since 6.5 + */ + @NonNull + public static ClientAuthenticationMethod valueOf(String method) { + for (ClientAuthenticationMethod m : methods()) { + if (m.getValue().equals(method)) { + return m; + } + } + return new ClientAuthenticationMethod(method); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java index 0e8353e103..c698a6d5dc 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,13 @@ package org.springframework.security.oauth2.core; +import java.util.stream.Stream; + +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; + +import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -69,4 +75,23 @@ public class ClientAuthenticationMethodTests { .isEqualTo("self_signed_tls_client_auth"); } + @Test + public void valueOfWhenAnyAuthenticationMethodThenConstructs() { + String string = new String("any"); + ClientAuthenticationMethod method = ClientAuthenticationMethod.valueOf(string); + assertThat(method.getValue()).isSameAs(string); + } + + @TestFactory + Stream valueOfWhenMatchesStaticThenReturnsStatic() { + return Stream.of(ClientAuthenticationMethod.methods()) + .map((method) -> DynamicTest.dynamicTest(testName(method.getValue()), + () -> assertThat(ClientAuthenticationMethod.valueOf(method.getValue())).isSameAs(method))); + } + + String testName(String method) { + String methodName = StringUtils.capitalize(method.replaceAll("_", "")); + return "valueOfWhen" + methodName + "ThenReturnsStatic" + methodName; + } + } From 91b0936189ef6dc266f1a7b7974e2157255faa14 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:43:27 -0700 Subject: [PATCH 007/504] Add AssertionValidator - Ships with support for customizing the OpenSAML validators to use - Or, you can supply your own instance of SAML20AssertionValidator Closes gh-15578 --- .../servlet/saml2/login/authentication.adoc | 112 +++++ .../OpenSaml5AuthenticationProvider.java | 402 ++++++++++++++---- .../OpenSaml5AuthenticationProviderTests.java | 23 + 3 files changed, 450 insertions(+), 87 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index 29c67cc8dd..9fc64c2638 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -192,6 +192,64 @@ open class SecurityConfig { ---- ====== +If you are using xref:servlet/saml2/opensaml.adoc[OpenSAML 5], then we have a simpler way, using `OpenSaml5AuthenticationProvider.AssertionValidator`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + OpenSaml5AuthenticationProvider authenticationProvider = new OpenSaml5AuthenticationProvider(); + AssertionValidator assertionValidator = AssertionValidator.builder() + .clockSkew(Duration.ofMinutes(10)).build(); + authenticationProvider.setAssertionValidator(assertionValidator); + http + .authorizeHttpRequests(authz -> authz + .anyRequest().authenticated() + ) + .saml2Login(saml2 -> saml2 + .authenticationManager(new ProviderManager(authenticationProvider)) + ); + return http.build(); + } +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- + + +@Configuration @EnableWebSecurity +class SecurityConfig { + @Bean + @Throws(Exception::class) + fun filterChain(http: HttpSecurity): SecurityFilterChain { + val authenticationProvider = OpenSaml5AuthenticationProvider() + val assertionValidator = AssertionValidator.builder().clockSkew(Duration.ofMinutes(10)).build() + authenticationProvider.setAssertionValidator(assertionValidator) + http { + authorizeHttpRequests { + authorize(anyRequest, authenticated) + } + saml2Login { + authenticationManager = ProviderManager(authenticationProvider) + } + } + return http.build() + } +} +---- +====== + [[servlet-saml2login-opensamlauthenticationprovider-userdetailsservice]] == Coordinating with a `UserDetailsService` @@ -368,6 +426,60 @@ provider.setAssertionValidator { assertionToken -> While recommended, it's not necessary to call ``OpenSaml4AuthenticationProvider``'s default assertion validator. A circumstance where you would skip it would be if you don't need it to check the `` or the `` since you are doing those yourself. +If you are using xref:servlet/saml2/opensaml.adoc[OpenSAML 5], then we have a simpler way using `OpenSaml5AuthenticationProvider.AssertionValidator`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); +OneTimeUseConditionValidator validator = ...; +AssertionValidator assertionValidator = AssertionValidator.builder() + .conditionValidators((c) -> c.add(validator)).build(); +provider.setAssertionValidator(assertionValidator); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val provider = OpenSaml5AuthenticationProvider() +val validator: OneTimeUseConditionValidator = ...; +val assertionValidator = AssertionValidator.builder() + .conditionValidators { add(validator) }.build() +provider.setAssertionValidator(assertionValidator) +---- +====== + +You can use this same builder to remove validators that you don't want to use like so: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); +AssertionValidator assertionValidator = AssertionValidator.builder() + .conditionValidators((c) -> c.removeIf(AudienceRestrictionValidator.class::isInstance)).build(); +provider.setAssertionValidator(assertionValidator); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val provider = new OpenSaml5AuthenticationProvider() +val assertionValidator = AssertionValidator.builder() + .conditionValidators { + c: List -> c.removeIf { it is AudienceRestrictionValidator } + }.build() +provider.setAssertionValidator(assertionValidator) +---- +====== + [[servlet-saml2login-opensamlauthenticationprovider-decryption]] == Customizing Decryption diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java index fecaae570e..f6ca75e1cc 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java @@ -17,21 +17,40 @@ package org.springframework.security.saml2.provider.service.authentication; import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Consumer; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.xml.namespace.QName; + +import org.opensaml.saml.common.assertion.AssertionValidationException; import org.opensaml.saml.common.assertion.ValidationContext; import org.opensaml.saml.common.assertion.ValidationResult; +import org.opensaml.saml.saml2.assertion.ConditionValidator; import org.opensaml.saml.saml2.assertion.SAML20AssertionValidator; import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters; +import org.opensaml.saml.saml2.assertion.StatementValidator; +import org.opensaml.saml.saml2.assertion.SubjectConfirmationValidator; +import org.opensaml.saml.saml2.assertion.impl.AudienceRestrictionConditionValidator; +import org.opensaml.saml.saml2.assertion.impl.BearerSubjectConfirmationValidator; +import org.opensaml.saml.saml2.assertion.impl.DelegationRestrictionConditionValidator; +import org.opensaml.saml.saml2.assertion.impl.ProxyRestrictionConditionValidator; import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.Condition; import org.opensaml.saml.saml2.core.EncryptedAssertion; +import org.opensaml.saml.saml2.core.OneTimeUse; import org.opensaml.saml.saml2.core.Response; import org.opensaml.saml.saml2.core.SubjectConfirmation; import org.opensaml.saml.saml2.core.SubjectConfirmationData; import org.opensaml.saml.saml2.encryption.Decrypter; +import org.opensaml.xmlsec.signature.support.SignaturePrevalidator; +import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; @@ -95,7 +114,7 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv */ public OpenSaml5AuthenticationProvider() { this.delegate = new BaseOpenSamlAuthenticationProvider(new OpenSaml5Template()); - setAssertionValidator(createDefaultAssertionValidator()); + setAssertionValidator(AssertionValidator.withDefaults()); } /** @@ -173,14 +192,14 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * Set the {@link Converter} to use for validating each {@link Assertion} in the SAML * 2.0 Response. * - * You can still invoke the default validator by delgating to - * {@link #createAssertionValidator}, like so: + * You can still invoke the default validator by calling + * {@link AssertionValidator#withDefaults()}, like so: * *
 	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
+	 *  AssertionValidator validator = AssertionValidator.withDefaults();
 	 *  provider.setAssertionValidator(assertionToken -> {
-	 *		Saml2ResponseValidatorResult result = createDefaultAssertionValidator()
-	 *			.convert(assertionToken)
+	 *		Saml2ResponseValidatorResult result = validator.validate(assertionToken);
 	 *		return result.concat(myCustomValidator.convert(assertionToken));
 	 *  });
 	 * 
@@ -190,17 +209,12 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * *
 	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	provider.setAssertionValidator(
-	 *		createDefaultAssertionValidator(assertionToken -> {
-	 *			Map<String, Object> params = new HashMap<>();
-	 *			params.put(CLOCK_SKEW, 2 * 60 * 1000);
-	 *			// other parameters
-	 *			return new ValidationContext(params);
-	 *		}));
+	 *  AssertionValidator validator = AssertionValidator.builder().clockSkew(Duration.ofMinutes(2)).build();
+	 *	provider.setAssertionValidator(validator);
 	 * 
* - * Consider taking a look at {@link #createValidationContext} to see how it constructs - * a {@link ValidationContext}. + * Consider taking a look at {@link AssertionValidator#createValidationContext} to see + * how it constructs a {@link ValidationContext}. * * It is not necessary to delegate to the default validator. You can safely replace it * entirely with your own. Note that signature verification is performed as a separate @@ -299,10 +313,11 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * Construct a default strategy for validating each SAML 2.0 Assertion and associated * {@link Authentication} token * @return the default assertion validator strategy + * @deprecated please use {@link AssertionValidator#withDefaults()} instead */ + @Deprecated public static Converter createDefaultAssertionValidator() { - return createDefaultAssertionValidatorWithParameters( - (params) -> params.put(SAML2AssertionValidationParameters.CLOCK_SKEW, Duration.ofMinutes(5))); + return AssertionValidator.withDefaults(); } /** @@ -316,9 +331,25 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv @Deprecated public static Converter createDefaultAssertionValidator( Converter contextConverter) { - return createAssertionValidator(Saml2ErrorCodes.INVALID_ASSERTION, - (assertionToken) -> BaseOpenSamlAuthenticationProvider.SAML20AssertionValidators.attributeValidator, - contextConverter); + return (assertionToken) -> { + Assertion assertion = assertionToken.getAssertion(); + SAML20AssertionValidator validator = BaseOpenSamlAuthenticationProvider.SAML20AssertionValidators.attributeValidator; + ValidationContext context = contextConverter.convert(assertionToken); + try { + ValidationResult result = validator.validate(assertion, context); + if (result == ValidationResult.VALID) { + return Saml2ResponseValidatorResult.success(); + } + } + catch (Exception ex) { + String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), + ((Response) assertion.getParent()).getID(), ex.getMessage()); + return Saml2ResponseValidatorResult.failure(new Saml2Error(Saml2ErrorCodes.INVALID_ASSERTION, message)); + } + String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), + ((Response) assertion.getParent()).getID(), context.getValidationFailureMessages()); + return Saml2ResponseValidatorResult.failure(new Saml2Error(Saml2ErrorCodes.INVALID_ASSERTION, message)); + }; } /** @@ -328,12 +359,12 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * {@link ValidationContext} for each assertion being validated * @return the default assertion validator strategy * @since 5.8 + * @deprecated please use {@link AssertionValidator#withDefaults()} instead */ + @Deprecated public static Converter createDefaultAssertionValidatorWithParameters( Consumer> validationContextParameters) { - return createAssertionValidator(Saml2ErrorCodes.INVALID_ASSERTION, - (assertionToken) -> BaseOpenSamlAuthenticationProvider.SAML20AssertionValidators.attributeValidator, - (assertionToken) -> createValidationContext(assertionToken, validationContextParameters)); + return AssertionValidator.builder().validationContextParameters(validationContextParameters).build(); } /** @@ -364,71 +395,6 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv return authentication != null && Saml2AuthenticationToken.class.isAssignableFrom(authentication); } - private static Converter createAssertionValidator(String errorCode, - Converter validatorConverter, - Converter contextConverter) { - - return (assertionToken) -> { - Assertion assertion = assertionToken.getAssertion(); - SAML20AssertionValidator validator = validatorConverter.convert(assertionToken); - ValidationContext context = contextConverter.convert(assertionToken); - try { - ValidationResult result = validator.validate(assertion, context); - if (result == ValidationResult.VALID) { - return Saml2ResponseValidatorResult.success(); - } - } - catch (Exception ex) { - String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), - ((Response) assertion.getParent()).getID(), ex.getMessage()); - return Saml2ResponseValidatorResult.failure(new Saml2Error(errorCode, message)); - } - String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), - ((Response) assertion.getParent()).getID(), context.getValidationFailureMessages()); - return Saml2ResponseValidatorResult.failure(new Saml2Error(errorCode, message)); - }; - } - - private static ValidationContext createValidationContext(AssertionToken assertionToken, - Consumer> paramsConsumer) { - Saml2AuthenticationToken token = assertionToken.getToken(); - RelyingPartyRegistration relyingPartyRegistration = token.getRelyingPartyRegistration(); - String audience = relyingPartyRegistration.getEntityId(); - String recipient = relyingPartyRegistration.getAssertionConsumerServiceLocation(); - String assertingPartyEntityId = relyingPartyRegistration.getAssertingPartyMetadata().getEntityId(); - Map params = new HashMap<>(); - Assertion assertion = assertionToken.getAssertion(); - if (assertionContainsInResponseTo(assertion)) { - String requestId = getAuthnRequestId(token.getAuthenticationRequest()); - params.put(SAML2AssertionValidationParameters.SC_VALID_IN_RESPONSE_TO, requestId); - } - params.put(SAML2AssertionValidationParameters.COND_VALID_AUDIENCES, Collections.singleton(audience)); - params.put(SAML2AssertionValidationParameters.SC_VALID_RECIPIENTS, Collections.singleton(recipient)); - params.put(SAML2AssertionValidationParameters.VALID_ISSUERS, Collections.singleton(assertingPartyEntityId)); - paramsConsumer.accept(params); - return new ValidationContext(params); - } - - private static boolean assertionContainsInResponseTo(Assertion assertion) { - if (assertion.getSubject() == null) { - return false; - } - for (SubjectConfirmation confirmation : assertion.getSubject().getSubjectConfirmations()) { - SubjectConfirmationData confirmationData = confirmation.getSubjectConfirmationData(); - if (confirmationData == null) { - continue; - } - if (StringUtils.hasText(confirmationData.getInResponseTo())) { - return true; - } - } - return false; - } - - private static String getAuthnRequestId(AbstractSaml2AuthenticationRequest serialized) { - return (serialized != null) ? serialized.getId() : null; - } - /** * A tuple containing an OpenSAML {@link Response} and its associated authentication * token. @@ -493,4 +459,266 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv } + /** + * A default implementation of {@link OpenSaml5AuthenticationProvider}'s assertion + * validator. This does not check the signature as signature verification is performed + * by a different component + * + * @author Josh Cummings + * @since 6.5 + */ + public static final class AssertionValidator implements Converter { + + private final SAML20AssertionValidator assertionValidator; + + private Consumer> paramsConsumer = (map) -> { + }; + + public AssertionValidator(SAML20AssertionValidator assertionValidator) { + this.assertionValidator = assertionValidator; + } + + @Override + public Saml2ResponseValidatorResult convert(AssertionToken source) { + Assertion assertion = source.getAssertion(); + ValidationContext validationContext = createValidationContext(source); + try { + ValidationResult result = this.assertionValidator.validate(assertion, validationContext); + if (result == ValidationResult.VALID) { + return Saml2ResponseValidatorResult.success(); + } + } + catch (Exception ex) { + String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), + ((Response) assertion.getParent()).getID(), ex.getMessage()); + return Saml2ResponseValidatorResult.failure(new Saml2Error(Saml2ErrorCodes.INVALID_ASSERTION, message)); + } + String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(), + ((Response) assertion.getParent()).getID(), validationContext.getValidationFailureMessages()); + return Saml2ResponseValidatorResult.failure(new Saml2Error(Saml2ErrorCodes.INVALID_ASSERTION, message)); + } + + /** + * Validate this assertion + * @param token the assertion to validate + * @return the validation result + */ + public Saml2ResponseValidatorResult validate(AssertionToken token) { + return convert(token); + } + + /** + * Mutate the map of OpenSAML {@link ValidationContext} parameters using the given + * {@code paramsConsumer} + * @param paramsConsumer the context parameters mutator + */ + public void setValidationContextParameters(Consumer> paramsConsumer) { + this.paramsConsumer = paramsConsumer; + } + + private ValidationContext createValidationContext(AssertionToken assertionToken) { + Saml2AuthenticationToken token = assertionToken.getToken(); + RelyingPartyRegistration relyingPartyRegistration = token.getRelyingPartyRegistration(); + String audience = relyingPartyRegistration.getEntityId(); + String recipient = relyingPartyRegistration.getAssertionConsumerServiceLocation(); + String assertingPartyEntityId = relyingPartyRegistration.getAssertingPartyMetadata().getEntityId(); + Map params = new HashMap<>(); + Assertion assertion = assertionToken.getAssertion(); + if (assertionContainsInResponseTo(assertion)) { + String requestId = getAuthnRequestId(token.getAuthenticationRequest()); + params.put(SAML2AssertionValidationParameters.SC_VALID_IN_RESPONSE_TO, requestId); + } + params.put(SAML2AssertionValidationParameters.COND_VALID_AUDIENCES, Collections.singleton(audience)); + params.put(SAML2AssertionValidationParameters.SC_VALID_RECIPIENTS, Collections.singleton(recipient)); + params.put(SAML2AssertionValidationParameters.VALID_ISSUERS, Collections.singleton(assertingPartyEntityId)); + params.put(SAML2AssertionValidationParameters.SC_CHECK_ADDRESS, false); + this.paramsConsumer.accept(params); + return new ValidationContext(params); + } + + private static boolean assertionContainsInResponseTo(Assertion assertion) { + if (assertion.getSubject() == null) { + return false; + } + for (SubjectConfirmation confirmation : assertion.getSubject().getSubjectConfirmations()) { + SubjectConfirmationData confirmationData = confirmation.getSubjectConfirmationData(); + if (confirmationData == null) { + continue; + } + if (StringUtils.hasText(confirmationData.getInResponseTo())) { + return true; + } + } + return false; + } + + private static String getAuthnRequestId(AbstractSaml2AuthenticationRequest serialized) { + return (serialized != null) ? serialized.getId() : null; + } + + /** + * Create the default assertion validator + * @return the default assertion validator + */ + public static AssertionValidator withDefaults() { + return new Builder().build(); + } + + /** + * Use a builder to configure aspects of the validator + * @return the {@link Builder} for configuration {@link AssertionValidator} + */ + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + + private final List conditions = new ArrayList<>(); + + private final List subjects = new ArrayList<>(); + + private final Map validationParameters = new HashMap<>(); + + private Builder() { + this.conditions.add(new AudienceRestrictionConditionValidator()); + this.conditions.add(new DelegationRestrictionConditionValidator()); + this.conditions.add(new ValidConditionValidator(OneTimeUse.DEFAULT_ELEMENT_NAME)); + this.conditions.add(new ProxyRestrictionConditionValidator()); + this.subjects.add(new BearerSubjectConfirmationValidator()); + this.validationParameters.put(SAML2AssertionValidationParameters.CLOCK_SKEW, Duration.ofMinutes(5)); + } + + /** + * Use this clock skew for validating assertion timestamps. The default is 5 + * minutes. + * @param duration the duration to use + * @return the {@link Builder} for further configuration + */ + public Builder clockSkew(Duration duration) { + this.validationParameters.put(SAML2AssertionValidationParameters.CLOCK_SKEW, duration); + return this; + } + + /** + * Mutate the map of {@link ValidationContext} static parameters. By default, + * these include: + *
    + *
  • {@link SAML2AssertionValidationParameters#SC_VALID_IN_RESPONSE_TO}
  • > + *
  • {@link SAML2AssertionValidationParameters#COND_VALID_AUDIENCES}
  • > + *
  • {@link SAML2AssertionValidationParameters#SC_VALID_RECIPIENTS}
  • > + *
  • {@link SAML2AssertionValidationParameters#VALID_ISSUERS}
  • > + *
  • {@link SAML2AssertionValidationParameters#SC_CHECK_ADDRESS}
  • > + *
  • {@link SAML2AssertionValidationParameters#CLOCK_SKEW}
  • > + *
+ * + * Note that several of these are required by various validation steps, for + * example {@code COND_VALID_AUDIENCES} is needed by + * {@link BearerSubjectConfirmationValidator}. If you do not want these, the + * best way to remove them is to remove the {@link #conditionValidators} or + * {@link #subjectValidators} themselves + * @param parameters the mutator to change the set of parameters + * @return + */ + public Builder validationContextParameters(Consumer> parameters) { + parameters.accept(this.validationParameters); + return this; + } + + /** + * Mutate the list of {@link ConditionValidator}s. By default, these include: + *
    + *
  • {@link AudienceRestrictionConditionValidator}
  • + *
  • {@link DelegationRestrictionConditionValidator}
  • + *
  • {@link ProxyRestrictionConditionValidator}
  • + *
+ * Note that it also adds a validator that skips the {@code saml2:OneTimeUse} + * element since this validator does not have caching facilities. However, you + * can construct your own instance of + * {@link org.opensaml.saml.saml2.assertion.impl.OneTimeUseConditionValidator} + * and supply it here. + * @param conditions the mutator for changing the list of conditions to use + * @return the {@link Builder} for further configuration + */ + public Builder conditionValidators(Consumer> conditions) { + conditions.accept(this.conditions); + return this; + } + + /** + * Mutate the list of {@link ConditionValidator}s. + *

+ * By default it only has {@link BearerSubjectConfirmationValidator} for which + * address validation is skipped. + * + * To turn address validation on, use + * {@link #validationContextParameters(Consumer)} to set the + * {@link SAML2AssertionValidationParameters#SC_CHECK_ADDRESS} value. + * @param subjects the mutator for changing the list of conditions to use + * @return the {@link Builder} for further configuration + */ + public Builder subjectValidators(Consumer> subjects) { + subjects.accept(this.subjects); + return this; + } + + /** + * Build the {@link AssertionValidator} + * @return the {@link AssertionValidator} + */ + public AssertionValidator build() { + AssertionValidator validator = new AssertionValidator(new ValidSignatureAssertionValidator( + this.conditions, this.subjects, List.of(), null, null, null)); + validator.setValidationContextParameters((params) -> params.putAll(this.validationParameters)); + return validator; + } + + } + + private static final class ValidConditionValidator implements ConditionValidator { + + private final QName name; + + private ValidConditionValidator(QName name) { + this.name = name; + } + + @Nonnull + @Override + public QName getServicedCondition() { + return this.name; + } + + @Nonnull + @Override + public ValidationResult validate(@Nonnull Condition condition, @Nonnull Assertion assertion, + @Nonnull ValidationContext context) { + return ValidationResult.VALID; + } + + } + + private static final class ValidSignatureAssertionValidator extends SAML20AssertionValidator { + + private ValidSignatureAssertionValidator(@Nullable Collection newConditionValidators, + @Nullable Collection newConfirmationValidators, + @Nullable Collection newStatementValidators, + @Nullable org.opensaml.saml.saml2.assertion.AssertionValidator newAssertionValidator, + @Nullable SignatureTrustEngine newTrustEngine, + @Nullable SignaturePrevalidator newSignaturePrevalidator) { + super(newConditionValidators, newConfirmationValidators, newStatementValidators, newAssertionValidator, + newTrustEngine, newSignaturePrevalidator); + } + + @Nonnull + @Override + protected ValidationResult validateSignature(@Nonnull Assertion token, @Nonnull ValidationContext context) + throws AssertionValidationException { + return ValidationResult.VALID; + } + + } + + } + } diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index 22ed0e89b6..a0ef0de8cf 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -39,11 +39,14 @@ import org.opensaml.core.xml.schema.XSDateTime; import org.opensaml.core.xml.schema.impl.XSDateTimeBuilder; import org.opensaml.saml.common.SignableSAMLObject; import org.opensaml.saml.common.assertion.ValidationContext; +import org.opensaml.saml.common.assertion.ValidationResult; +import org.opensaml.saml.saml2.assertion.ConditionValidator; import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.core.AttributeStatement; import org.opensaml.saml.saml2.core.AttributeValue; +import org.opensaml.saml.saml2.core.AudienceRestriction; import org.opensaml.saml.saml2.core.Conditions; import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.EncryptedAttribute; @@ -73,6 +76,7 @@ import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; import org.springframework.security.saml2.core.TestSaml2X509Credentials; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.AssertionValidator; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseToken; import org.springframework.security.saml2.provider.service.authentication.TestCustomOpenSaml5Objects.CustomOpenSamlObject; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -556,6 +560,25 @@ public class OpenSaml5AuthenticationProviderTests { verify(validator).convert(any(OpenSaml5AuthenticationProvider.AssertionToken.class)); } + @Test + public void authenticateWhenAssertionValidatorListThenUses() throws Exception { + ConditionValidator custom = mock(ConditionValidator.class); + given(custom.getServicedCondition()).willReturn(AudienceRestriction.DEFAULT_ELEMENT_NAME); + given(custom.validate(any(), any(), any())).willReturn(ValidationResult.INVALID); + AssertionValidator validator = AssertionValidator.builder().conditionValidators((c) -> c.add(custom)).build(); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setAssertionValidator(validator); + Response response = TestOpenSamlObjects.signedResponseWithOneAssertion((r) -> r.getAssertions() + .get(0) + .getConditions() + .getConditions() + .add(build(AudienceRestriction.DEFAULT_ELEMENT_NAME))); + Saml2AuthenticationToken token = token(response, verifying(registration())); + assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token)) + .withMessageContaining("AudienceRestriction"); + verify(custom).validate(any(), any(), any()); + } + @Test public void authenticateWhenDefaultConditionValidatorNotUsedThenSignatureStillChecked() { OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); From 616b43f2612d80bae7f5db8112935610e7d73a3b Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 11:02:46 -0600 Subject: [PATCH 008/504] Restore 6.x Migration Steps Issue gh-16873 --- docs/modules/ROOT/nav.adoc | 2 +- docs/modules/ROOT/pages/migration/index.adoc | 38 ++-- .../ROOT/pages/migration/reactive.adoc | 100 ++++++++++ .../migration/servlet/authentication.adoc | 187 ++++++++++++++++++ .../migration/servlet/authorization.adoc | 136 +++++++++++++ .../pages/migration/servlet/exploits.adoc | 44 +++++ .../ROOT/pages/migration/servlet/index.adoc | 4 + .../migration/servlet/session-management.adoc | 49 +++++ 8 files changed, 546 insertions(+), 14 deletions(-) create mode 100644 docs/modules/ROOT/pages/migration/reactive.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/authentication.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/authorization.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/exploits.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/index.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/session-management.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 37052965b8..a01642dc64 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -5,7 +5,7 @@ * xref:migration-7/index.adoc[Preparing for 7.0] ** xref:migration-7/configuration.adoc[Configuration] ** xref:migration-7/ldap.adoc[LDAP] -* xref:migration/index.adoc[Migrating to 6.2] +* xref:migration/index.adoc[Migrating to 6] ** xref:migration/authorization.adoc[Authorization Changes] * xref:getting-spring-security.adoc[Getting Spring Security] * xref:features/index.adoc[Features] diff --git a/docs/modules/ROOT/pages/migration/index.adoc b/docs/modules/ROOT/pages/migration/index.adoc index 3f7954e7d6..db1d8d1333 100644 --- a/docs/modules/ROOT/pages/migration/index.adoc +++ b/docs/modules/ROOT/pages/migration/index.adoc @@ -1,23 +1,35 @@ [[migration]] -= Migrating to 6.2 += Migrating to 6.0 :spring-security-reference-base-url: https://docs.spring.io/spring-security/reference -This guide provides instructions for migrating from Spring Security 6.1 to Spring Security 6.2. +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. -== Update to Spring Security 6.2 +After updating to 5.8, follow this guide to perform any remaining migration or cleanup steps. -When updating to a new minor version, it is important that you are already using the latest patch release of the previous minor version. -For example, if you are upgrading to Spring Security 6.2, you should already be using the latest patch release of Spring Security 6.1. -This makes it easier to identify any changes that may have been introduced in the new minor version. +And recall that if you run into trouble, the preparation guide includes opt-out steps to revert to 5.x behaviors. -Therefore, the first step is to ensure you are on the latest patch release of Spring Boot 3.1. -Next, you should ensure you are on the latest patch release of Spring Security 6.1. -Typically, the latest patch release of Spring Boot uses the latest patch release of Spring Security. +== Update to Spring Security 6 -With those two steps complete, you can now update to Spring Security 6.2. +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. -== Quick Reference +== Update Package Names -The following list provide a quick reference for the changes that are described in this guide. +Now that you are updated, you need to change your `javax` imports to `jakarta` imports. -- xref:migration/authorization.adoc#compile-with-parameters[You are using method parameter names in `@PreAuthorize`, `@PostAuthorize`, or any other method security annotations] +== 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`]. + +== Perform Application-Specific Steps + +Next, there are steps you need to perform based on whether it is a xref:migration/servlet/index.adoc[Servlet] or xref:migration/reactive.adoc[Reactive] application. diff --git a/docs/modules/ROOT/pages/migration/reactive.adoc b/docs/modules/ROOT/pages/migration/reactive.adoc new file mode 100644 index 0000000000..370e52262f --- /dev/null +++ b/docs/modules/ROOT/pages/migration/reactive.adoc @@ -0,0 +1,100 @@ += 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 new file mode 100644 index 0000000000..3db94cf7a6 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/authentication.adoc @@ -0,0 +1,187 @@ += 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 new file mode 100644 index 0000000000..0f60a2f4c1 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/authorization.adoc @@ -0,0 +1,136 @@ += 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 new file mode 100644 index 0000000000..bddafec6c2 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/exploits.adoc @@ -0,0 +1,44 @@ += 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/index.adoc b/docs/modules/ROOT/pages/migration/servlet/index.adoc new file mode 100644 index 0000000000..adc75685a6 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/index.adoc @@ -0,0 +1,4 @@ += Servlet Migrations +:page-section-summary-toc: 1 + +If you have already performed the xref:migration/index.adoc[initial migration steps] for your Servlet application, you're now ready to perform steps specific to Servlet applications. diff --git a/docs/modules/ROOT/pages/migration/servlet/session-management.adoc b/docs/modules/ROOT/pages/migration/servlet/session-management.adoc new file mode 100644 index 0000000000..c7409b9e07 --- /dev/null +++ b/docs/modules/ROOT/pages/migration/servlet/session-management.adoc @@ -0,0 +1,49 @@ += 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[] From f2805935664ee2714b5543342a85678a9fe07a25 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 11:03:29 -0600 Subject: [PATCH 009/504] Move Preparation Steps Closes gh-16873 --- docs/modules/ROOT/nav.adoc | 3 + .../authentication.adoc | 0 .../authorization.adoc | 0 .../{migration => migration-7}/oauth2.adoc | 0 docs/modules/ROOT/pages/migration-7/web.adoc | 328 +++++++++++++++++ docs/modules/ROOT/pages/migration/web.adoc | 330 ------------------ 6 files changed, 331 insertions(+), 330 deletions(-) rename docs/modules/ROOT/pages/{migration => migration-7}/authentication.adoc (100%) rename docs/modules/ROOT/pages/{migration => migration-7}/authorization.adoc (100%) rename docs/modules/ROOT/pages/{migration => migration-7}/oauth2.adoc (100%) delete mode 100644 docs/modules/ROOT/pages/migration/web.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 3fc74ae93d..d65fc977c0 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -3,8 +3,11 @@ * 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:getting-spring-security.adoc[Getting Spring Security] diff --git a/docs/modules/ROOT/pages/migration/authentication.adoc b/docs/modules/ROOT/pages/migration-7/authentication.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/authentication.adoc rename to docs/modules/ROOT/pages/migration-7/authentication.adoc diff --git a/docs/modules/ROOT/pages/migration/authorization.adoc b/docs/modules/ROOT/pages/migration-7/authorization.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/authorization.adoc rename to docs/modules/ROOT/pages/migration-7/authorization.adoc diff --git a/docs/modules/ROOT/pages/migration/oauth2.adoc b/docs/modules/ROOT/pages/migration-7/oauth2.adoc similarity index 100% rename from docs/modules/ROOT/pages/migration/oauth2.adoc rename to docs/modules/ROOT/pages/migration-7/oauth2.adoc diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc index c3c201d5a1..aa898da4fd 100644 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ b/docs/modules/ROOT/pages/migration-7/web.adoc @@ -145,3 +145,331 @@ Xml:: ---- ====== +[[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")) +---- +====== + +== 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.servletPath("/mvc"); +http + .authorizeHttpRequests((authorize) -> authorize + .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated() + ) +---- + + +For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead: + +[method,java] +---- +PathPatternRequestParser.Builder request = PathPatternRequestParser.path(); +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/web.adoc b/docs/modules/ROOT/pages/migration/web.adoc deleted file mode 100644 index 1ea4ecbfc7..0000000000 --- a/docs/modules/ROOT/pages/migration/web.adoc +++ /dev/null @@ -1,330 +0,0 @@ -= Web Migrations - -[[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")) ----- -====== - -== 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.servletPath("/mvc"); -http - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated() - ) ----- - - -For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead: - -[method,java] ----- -PathPatternRequestParser.Builder request = PathPatternRequestParser.path(); -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. -===== From 04d71309759a8ff76486d6bc2604498e96a53534 Mon Sep 17 00:00:00 2001 From: Vasanth <76898064+vasanth-79@users.noreply.github.com> Date: Wed, 2 Apr 2025 11:47:33 +0530 Subject: [PATCH 010/504] Update WebAuthn Test Objects Class Names Renamed the WebAuthn test object class names Closes gh-16604 Signed-off-by: Vasanth <76898064+vasanth-79@users.noreply.github.com> --- ...gSecurityCoreVersionSerializableTests.java | 10 +-- ...estAuthenticatorAttestationResponses.java} | 4 +- ...Record.java => TestCredentialRecords.java} | 4 +- ... TestPublicKeyCredentialUserEntities.java} | 4 +- ...ial.java => TestPublicKeyCredentials.java} | 6 +- .../WebAuthnAuthenticationFilterTests.java | 4 +- .../WebAuthnAuthenticationTests.java | 8 +-- ...eyCredentialUserEntityRepositoryTests.java | 14 ++--- .../JdbcUserCredentialRepositoryTests.java | 14 ++--- ...eyCredentialUserEntityRepositoryTests.java | 6 +- .../MapUserCredentialRepositoryTests.java | 14 ++--- ...=> TestPublicKeyCredentialRpEntities.java} | 4 +- ...Webauthn4jRelyingPartyOperationsTests.java | 62 +++++++++---------- ...RegistrationPageGeneratingFilterTests.java | 12 ++-- .../WebAuthnRegistrationFilterTests.java | 4 +- 15 files changed, 85 insertions(+), 85 deletions(-) rename web/src/test/java/org/springframework/security/web/webauthn/api/{TestAuthenticatorAttestationResponse.java => TestAuthenticatorAttestationResponses.java} (93%) rename web/src/test/java/org/springframework/security/web/webauthn/api/{TestCredentialRecord.java => TestCredentialRecords.java} (96%) rename web/src/test/java/org/springframework/security/web/webauthn/api/{TestPublicKeyCredentialUserEntity.java => TestPublicKeyCredentialUserEntities.java} (90%) rename web/src/test/java/org/springframework/security/web/webauthn/api/{TestPublicKeyCredential.java => TestPublicKeyCredentials.java} (95%) rename web/src/test/java/org/springframework/security/web/webauthn/management/{TestPublicKeyCredentialRpEntity.java => TestPublicKeyCredentialRpEntities.java} (90%) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index 91dcddd990..07ecb3b7db 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -239,9 +239,9 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses; import org.springframework.security.web.webauthn.api.TestBytes; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; @@ -640,7 +640,7 @@ class SpringSecurityCoreVersionSerializableTests { AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput); AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse() .build(); - PublicKeyCredential credential = TestPublicKeyCredential.createPublicKeyCredential( + PublicKeyCredential credential = TestPublicKeyCredentials.createPublicKeyCredential( response, outputs) .build(); RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest( @@ -658,9 +658,9 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM); // @formatter:on generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, - (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); + (r) -> TestPublicKeyCredentialUserEntities.userEntity().id(TestBytes.get()).build()); generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity() .id(TestBytes.get()) .build(); List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponse.java b/web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponses.java similarity index 93% rename from web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponse.java rename to web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponses.java index 0d240c959b..ea3e3de9c3 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponse.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/api/TestAuthenticatorAttestationResponses.java @@ -16,7 +16,7 @@ package org.springframework.security.web.webauthn.api; -public final class TestAuthenticatorAttestationResponse { +public final class TestAuthenticatorAttestationResponses { public static AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder createAuthenticatorAttestationResponse() { return AuthenticatorAttestationResponse.builder() @@ -27,7 +27,7 @@ public final class TestAuthenticatorAttestationResponse { .transports(AuthenticatorTransport.HYBRID, AuthenticatorTransport.INTERNAL); } - private TestAuthenticatorAttestationResponse() { + private TestAuthenticatorAttestationResponses() { } } diff --git a/web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecord.java b/web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecords.java similarity index 96% rename from web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecord.java rename to web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecords.java index 1ed190c03d..7284c12ea9 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecord.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/api/TestCredentialRecords.java @@ -19,7 +19,7 @@ package org.springframework.security.web.webauthn.api; import java.time.Instant; import java.util.Set; -public final class TestCredentialRecord { +public final class TestCredentialRecords { public static ImmutableCredentialRecord.ImmutableCredentialRecordBuilder userCredential() { return ImmutableCredentialRecord.builder() @@ -50,7 +50,7 @@ public final class TestCredentialRecord { .backupState(true); } - private TestCredentialRecord() { + private TestCredentialRecords() { } } diff --git a/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntity.java b/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntities.java similarity index 90% rename from web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntity.java rename to web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntities.java index cc35752d15..dbf7a2f06c 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntity.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentialUserEntities.java @@ -18,13 +18,13 @@ package org.springframework.security.web.webauthn.api; import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.PublicKeyCredentialUserEntityBuilder; -public final class TestPublicKeyCredentialUserEntity { +public final class TestPublicKeyCredentialUserEntities { public static PublicKeyCredentialUserEntityBuilder userEntity() { return ImmutablePublicKeyCredentialUserEntity.builder().name("user").id(TestBytes.get()).displayName("user"); } - private TestPublicKeyCredentialUserEntity() { + private TestPublicKeyCredentialUserEntities() { } } diff --git a/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredential.java b/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentials.java similarity index 95% rename from web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredential.java rename to web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentials.java index 5ae19ac23c..208e46c444 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredential.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/api/TestPublicKeyCredentials.java @@ -16,10 +16,10 @@ package org.springframework.security.web.webauthn.api; -public final class TestPublicKeyCredential { +public final class TestPublicKeyCredentials { public static PublicKeyCredential.PublicKeyCredentialBuilder createPublicKeyCredential() { - AuthenticatorAttestationResponse response = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponse response = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse() .build(); return createPublicKeyCredential(response); @@ -49,7 +49,7 @@ public final class TestPublicKeyCredential { .clientExtensionResults(outputs); } - private TestPublicKeyCredential() { + private TestPublicKeyCredentials() { } } diff --git a/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java index 244e06a060..beff88377a 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java @@ -39,7 +39,7 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredential; import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @@ -153,7 +153,7 @@ class WebAuthnAuthenticationFilterTests { void doFilterWhenValidThenOk() throws Exception { PublicKeyCredentialRequestOptions options = TestPublicKeyCredentialRequestOptions.create().build(); given(this.requestOptionsRepository.load(any())).willReturn(options); - PublicKeyCredentialUserEntity principal = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity principal = TestPublicKeyCredentialUserEntities.userEntity().build(); WebAuthnAuthentication authentication = new WebAuthnAuthentication(principal, AuthorityUtils.createAuthorityList("ROLE_USER")); given(this.authenticationManager.authenticate(any())).willReturn(authentication); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationTests.java b/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationTests.java index c10240a7f2..3c2f37bf3c 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationTests.java @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -32,7 +32,7 @@ class WebAuthnAuthenticationTests { @Test void isAuthenticatedThenTrue() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); WebAuthnAuthentication authentication = new WebAuthnAuthentication(userEntity, authorities); assertThat(authentication.isAuthenticated()).isTrue(); @@ -40,7 +40,7 @@ class WebAuthnAuthenticationTests { @Test void setAuthenticationWhenTrueThenException() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); WebAuthnAuthentication authentication = new WebAuthnAuthentication(userEntity, authorities); assertThatIllegalArgumentException().isThrownBy(() -> authentication.setAuthenticated(true)); @@ -48,7 +48,7 @@ class WebAuthnAuthenticationTests { @Test void setAuthenticationWhenFalseThenNotAuthenticated() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); WebAuthnAuthentication authentication = new WebAuthnAuthentication(userEntity, authorities); authentication.setAuthenticated(false); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcPublicKeyCredentialUserEntityRepositoryTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcPublicKeyCredentialUserEntityRepositoryTests.java index 503108ac4e..87e439b78c 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcPublicKeyCredentialUserEntityRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcPublicKeyCredentialUserEntityRepositoryTests.java @@ -28,7 +28,7 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.security.web.webauthn.api.Bytes; import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -107,7 +107,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void saveUserEntityWhenSaveThenReturnsSaved() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); this.repository.save(userEntity); @@ -120,7 +120,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void saveUserEntityWhenUserEntityExistsThenUpdates() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); this.repository.save(userEntity); this.repository.save(testUserEntity(userEntity.getId())); @@ -134,7 +134,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void findUserEntityByUserNameWhenUserEntityExistsThenReturnsSaved() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); this.repository.save(userEntity); PublicKeyCredentialUserEntity savedUserEntity = this.repository.findByUsername(userEntity.getName()); @@ -144,7 +144,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void deleteUserEntityWhenRecordExistThenSuccess() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); this.repository.save(userEntity); this.repository.delete(userEntity.getId()); @@ -155,7 +155,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void findUserEntityByIdWhenUserEntityDoesNotExistThenReturnsNull() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); PublicKeyCredentialUserEntity savedUserEntity = this.repository.findById(userEntity.getId()); assertThat(savedUserEntity).isNull(); @@ -163,7 +163,7 @@ public class JdbcPublicKeyCredentialUserEntityRepositoryTests { @Test void findUserEntityByUserNameWhenUserEntityDoesNotExistThenReturnsEmpty() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); PublicKeyCredentialUserEntity savedUserEntity = this.repository.findByUsername(userEntity.getName()); assertThat(savedUserEntity).isNull(); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepositoryTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepositoryTests.java index 3f495c2455..6754ec765c 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepositoryTests.java @@ -31,7 +31,7 @@ import org.springframework.security.web.webauthn.api.AuthenticatorTransport; import org.springframework.security.web.webauthn.api.CredentialRecord; import org.springframework.security.web.webauthn.api.ImmutableCredentialRecord; import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; -import org.springframework.security.web.webauthn.api.TestCredentialRecord; +import org.springframework.security.web.webauthn.api.TestCredentialRecords; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -110,7 +110,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void saveCredentialRecordWhenSaveThenReturnsSaved() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); this.jdbcUserCredentialRepository.save(userCredential); CredentialRecord savedUserCredential = this.jdbcUserCredentialRepository @@ -136,7 +136,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void saveCredentialRecordWhenRecordExistsThenReturnsUpdated() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); this.jdbcUserCredentialRepository.save(userCredential); // @formatter:off CredentialRecord updatedRecord = ImmutableCredentialRecord.fromCredentialRecord(userCredential) @@ -157,7 +157,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void findCredentialRecordByUserIdWhenRecordExistsThenReturnsSaved() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); this.jdbcUserCredentialRepository.save(userCredential); List credentialRecords = this.jdbcUserCredentialRepository @@ -169,7 +169,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void findCredentialRecordByUserIdWhenRecordDoesNotExistThenReturnsEmpty() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); List credentialRecords = this.jdbcUserCredentialRepository .findByUserId(userCredential.getUserEntityUserId()); @@ -179,7 +179,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void findCredentialRecordByCredentialIdWhenRecordDoesNotExistThenReturnsNull() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); CredentialRecord credentialRecord = this.jdbcUserCredentialRepository .findByCredentialId(userCredential.getCredentialId()); @@ -189,7 +189,7 @@ public class JdbcUserCredentialRepositoryTests { @Test void deleteCredentialRecordWhenRecordExistThenSuccess() { - CredentialRecord userCredential = TestCredentialRecord.fullUserCredential().build(); + CredentialRecord userCredential = TestCredentialRecords.fullUserCredential().build(); this.jdbcUserCredentialRepository.save(userCredential); this.jdbcUserCredentialRepository.delete(userCredential.getCredentialId()); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/MapPublicKeyCredentialUserEntityRepositoryTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/MapPublicKeyCredentialUserEntityRepositoryTests.java index df19491418..dde2b75086 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/MapPublicKeyCredentialUserEntityRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/MapPublicKeyCredentialUserEntityRepositoryTests.java @@ -19,7 +19,7 @@ package org.springframework.security.web.webauthn.management; import org.junit.jupiter.api.Test; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; @@ -36,7 +36,7 @@ class MapPublicKeyCredentialUserEntityRepositoryTests { private String username = "username"; - private PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() + private PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity() .name(this.username) .build(); @@ -75,7 +75,7 @@ class MapPublicKeyCredentialUserEntityRepositoryTests { @Test void saveWhenUpdateThenUpdated() { - PublicKeyCredentialUserEntity newUserEntity = TestPublicKeyCredentialUserEntity.userEntity() + PublicKeyCredentialUserEntity newUserEntity = TestPublicKeyCredentialUserEntities.userEntity() .name(this.userEntity.getName()) .displayName("Updated") .build(); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/MapUserCredentialRepositoryTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/MapUserCredentialRepositoryTests.java index d14e98df12..48fc888ad3 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/MapUserCredentialRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/MapUserCredentialRepositoryTests.java @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test; import org.springframework.security.web.webauthn.api.CredentialRecord; import org.springframework.security.web.webauthn.api.ImmutableCredentialRecord; import org.springframework.security.web.webauthn.api.TestBytes; -import org.springframework.security.web.webauthn.api.TestCredentialRecord; +import org.springframework.security.web.webauthn.api.TestCredentialRecords; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -61,7 +61,7 @@ class MapUserCredentialRepositoryTests { @Test void deleteWhenCredentialNotFoundThenNoException() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); assertThatNoException().isThrownBy(() -> this.userCredentials.delete(credentialRecord.getCredentialId())); } @@ -72,7 +72,7 @@ class MapUserCredentialRepositoryTests { @Test void saveThenFound() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); this.userCredentials.save(credentialRecord); assertThat(this.userCredentials.findByCredentialId(credentialRecord.getCredentialId())) .isEqualTo(credentialRecord); @@ -87,7 +87,7 @@ class MapUserCredentialRepositoryTests { @Test void saveAndDeleteThenNotFound() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); this.userCredentials.save(credentialRecord); this.userCredentials.delete(credentialRecord.getCredentialId()); assertThat(this.userCredentials.findByCredentialId(credentialRecord.getCredentialId())).isNull(); @@ -96,7 +96,7 @@ class MapUserCredentialRepositoryTests { @Test void saveWhenUpdateThenUpdated() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); this.userCredentials.save(credentialRecord); Instant updatedLastUsed = credentialRecord.getLastUsed().plusSeconds(120); CredentialRecord updatedCredentialRecord = ImmutableCredentialRecord.fromCredentialRecord(credentialRecord) @@ -111,7 +111,7 @@ class MapUserCredentialRepositoryTests { @Test void saveWhenSameUserThenUpdated() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); this.userCredentials.save(credentialRecord); CredentialRecord newCredentialRecord = ImmutableCredentialRecord.fromCredentialRecord(credentialRecord) .credentialId(TestBytes.get()) @@ -127,7 +127,7 @@ class MapUserCredentialRepositoryTests { @Test void saveWhenDifferentUserThenNewEntryAdded() { - ImmutableCredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); this.userCredentials.save(credentialRecord); CredentialRecord newCredentialRecord = ImmutableCredentialRecord.fromCredentialRecord(credentialRecord) .userEntityUserId(TestBytes.get()) diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntity.java b/web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntities.java similarity index 90% rename from web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntity.java rename to web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntities.java index 79c66c589f..1aa1ecb886 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntity.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/TestPublicKeyCredentialRpEntities.java @@ -18,13 +18,13 @@ package org.springframework.security.web.webauthn.management; import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity; -public final class TestPublicKeyCredentialRpEntity { +public final class TestPublicKeyCredentialRpEntities { public static PublicKeyCredentialRpEntity.PublicKeyCredentialRpEntityBuilder createRpEntity() { return PublicKeyCredentialRpEntity.builder().id("example.localhost").name("Spring Security Relying Party"); } - private TestPublicKeyCredentialRpEntity() { + private TestPublicKeyCredentialRpEntities() { } } diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java index 733d7ec98b..f60f7377d9 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java @@ -57,11 +57,11 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialParamete import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions; import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestAuthenticatorAttestationResponse; -import org.springframework.security.web.webauthn.api.TestCredentialRecord; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; +import org.springframework.security.web.webauthn.api.TestAuthenticatorAttestationResponses; +import org.springframework.security.web.webauthn.api.TestCredentialRecords; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import static org.assertj.core.api.Assertions.assertThat; @@ -93,7 +93,7 @@ class Webauthn4jRelyingPartyOperationsTests { private UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - private PublicKeyCredentialRpEntity rpEntity = TestPublicKeyCredentialRpEntity.createRpEntity().build(); + private PublicKeyCredentialRpEntity rpEntity = TestPublicKeyCredentialRpEntities.createRpEntity().build(); private Webauthn4JRelyingPartyOperations rpOperations; @@ -158,7 +158,7 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions expectedCreationOptions = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .rp(this.rpEntity) - .user(TestPublicKeyCredentialUserEntity.userEntity().build()) + .user(TestPublicKeyCredentialUserEntities.userEntity().build()) .build(); PublicKeyCredentialCreationOptions creationOptions = this.rpOperations.createPublicKeyCredentialCreationOptions( new ImmutablePublicKeyCredentialCreationOptionsRequest(this.user)); @@ -205,8 +205,8 @@ class Webauthn4jRelyingPartyOperationsTests { @Test void createPublicKeyCredentialCreationOptionsWhenExcludesThenSuccess() { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); - CredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); + CredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder() .id(credentialRecord.getCredentialId()) .transports(credentialRecord.getTransports()) @@ -233,7 +233,7 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - PublicKeyCredential publicKeyCredential = TestPublicKeyCredential + PublicKeyCredential publicKeyCredential = TestPublicKeyCredentials .createPublicKeyCredential() .build(); RelyingPartyPublicKey rpPublicKey = new RelyingPartyPublicKey(publicKeyCredential, this.label); @@ -252,11 +252,11 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - AuthenticatorAttestationResponse response = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponse response = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse() .transports(AuthenticatorTransport.INTERNAL) .build(); - PublicKeyCredential publicKeyCredential = TestPublicKeyCredential + PublicKeyCredential publicKeyCredential = TestPublicKeyCredentials .createPublicKeyCredential() .response(response) .build(); @@ -274,7 +274,7 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - PublicKeyCredential publicKeyCredential = TestPublicKeyCredential + PublicKeyCredential publicKeyCredential = TestPublicKeyCredentials .createPublicKeyCredential() .build(); RelyingPartyPublicKey rpPublicKey = new RelyingPartyPublicKey(publicKeyCredential, this.label); @@ -282,7 +282,7 @@ class Webauthn4jRelyingPartyOperationsTests { ImmutableRelyingPartyRegistrationRequest rpRegistrationRequest = new ImmutableRelyingPartyRegistrationRequest( creationOptions, rpPublicKey); given(this.userCredentials.findByCredentialId(publicKeyCredential.getRawId())) - .willReturn(TestCredentialRecord.userCredential().build()); + .willReturn(TestCredentialRecords.userCredential().build()); assertThatRuntimeException().isThrownBy(() -> this.rpOperations.registerCredential(rpRegistrationRequest)); } @@ -297,15 +297,15 @@ class Webauthn4jRelyingPartyOperationsTests { .createPublicKeyCredentialCreationOptions() .build(); String originalClientDataJSON = new String( - TestAuthenticatorAttestationResponse.createAuthenticatorAttestationResponse() + TestAuthenticatorAttestationResponses.createAuthenticatorAttestationResponse() .build() .getClientDataJSON() .getBytes()); String invalidTypeClientDataJSON = originalClientDataJSON.replace("webauthn.create", "webauthn.INVALID"); - AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse() .clientDataJSON(new Bytes(invalidTypeClientDataJSON.getBytes(StandardCharsets.UTF_8))); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); assertThatRuntimeException().isThrownBy(() -> this.rpOperations.registerCredential(registrationRequest)) @@ -325,9 +325,9 @@ class Webauthn4jRelyingPartyOperationsTests { // change the expected challenge so it does not match .challenge(Bytes.fromBase64("h0vgwGQjoCzAzDUsmzPpk-JVIJRRgn0L4KVSYNRcEZc")) .build(); - AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -348,9 +348,9 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -373,9 +373,9 @@ class Webauthn4jRelyingPartyOperationsTests { .createPublicKeyCredentialCreationOptions() .rp(PublicKeyCredentialRpEntity.builder().id("invalid").name("Spring Security").build()) .build(); - AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -394,7 +394,7 @@ class Webauthn4jRelyingPartyOperationsTests { .createPublicKeyCredentialCreationOptions() .build(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(setFlag(UP)).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(setFlag(UP)).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -416,7 +416,7 @@ class Webauthn4jRelyingPartyOperationsTests { .userVerification(UserVerificationRequirement.REQUIRED) .build()) .build(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(setFlag(UV)).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(setFlag(UV)).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -435,7 +435,7 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential(setFlag(BE)).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(setFlag(BE)).build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -478,7 +478,7 @@ class Webauthn4jRelyingPartyOperationsTests { .createPublicKeyCredentialCreationOptions() .pubKeyCredParams(PublicKeyCredentialParameters.RS1) .build(); - PublicKeyCredential publicKey = TestPublicKeyCredential + PublicKeyCredential publicKey = TestPublicKeyCredentials .createPublicKeyCredential() .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( @@ -516,7 +516,7 @@ class Webauthn4jRelyingPartyOperationsTests { PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions .createPublicKeyCredentialCreationOptions() .build(); - PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential() // setFmt("packed") + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential() // setFmt("packed") .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -570,8 +570,8 @@ class Webauthn4jRelyingPartyOperationsTests { UserDetails user = PasswordEncodedUser.user(); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build(); - CredentialRecord credentialRecord = TestCredentialRecord.userCredential().build(); + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntities.userEntity().build(); + CredentialRecord credentialRecord = TestCredentialRecords.userCredential().build(); given(this.userEntities.findByUsername(user.getUsername())).willReturn(userEntity); given(this.userCredentials.findByUserId(userEntity.getId())).willReturn(Arrays.asList(credentialRecord)); PublicKeyCredentialRequestOptionsRequest createRequest = new ImmutablePublicKeyCredentialRequestOptionsRequest( @@ -584,7 +584,7 @@ class Webauthn4jRelyingPartyOperationsTests { } private static AuthenticatorAttestationResponse setFlag(byte... flags) throws Exception { - AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); byte[] originalAttestationObjBytes = authAttResponseBldr.build().getAttestationObject().getBytes(); ObjectMapper cbor = cbor(); @@ -610,7 +610,7 @@ class Webauthn4jRelyingPartyOperationsTests { } private static AuthenticatorAttestationResponse setFmt(String fmt) throws Exception { - AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponse + AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); byte[] originalAttestationObjBytes = authAttResponseBldr.build().getAttestationObject().getBytes(); ObjectMapper cbor = cbor(); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/registration/DefaultWebAuthnRegistrationPageGeneratingFilterTests.java b/web/src/test/java/org/springframework/security/web/webauthn/registration/DefaultWebAuthnRegistrationPageGeneratingFilterTests.java index 7f681cc1dc..689628fcd4 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/registration/DefaultWebAuthnRegistrationPageGeneratingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/registration/DefaultWebAuthnRegistrationPageGeneratingFilterTests.java @@ -35,7 +35,7 @@ import org.springframework.security.web.webauthn.api.ImmutableCredentialRecord; import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.TestBytes; -import org.springframework.security.web.webauthn.api.TestCredentialRecord; +import org.springframework.security.web.webauthn.api.TestCredentialRecords; import org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository; import org.springframework.security.web.webauthn.management.UserCredentialRepository; import org.springframework.test.web.servlet.MockMvc; @@ -93,7 +93,7 @@ class DefaultWebAuthnRegistrationPageGeneratingFilterTests { .build(); given(this.userEntities.findByUsername(any())).willReturn(userEntity); given(this.userCredentials.findByUserId(userEntity.getId())) - .willReturn(Arrays.asList(TestCredentialRecord.userCredential().build())); + .willReturn(Arrays.asList(TestCredentialRecords.userCredential().build())); String body = bodyAsString(matchingRequest()); assertThat(body).contains("setupRegistration({\"X-CSRF-TOKEN\" : \"CSRF_TOKEN\"}"); assertThat(body.replaceAll("\\s", "")).contains(""" @@ -133,7 +133,7 @@ class DefaultWebAuthnRegistrationPageGeneratingFilterTests { .displayName("User") .build(); - ImmutableCredentialRecord credential = TestCredentialRecord.userCredential() + ImmutableCredentialRecord credential = TestCredentialRecords.userCredential() .created(LocalDateTime.of(2024, 9, 17, 10, 10, 42, 999_999_999).toInstant(ZoneOffset.UTC)) .lastUsed(LocalDateTime.of(2024, 9, 18, 11, 11, 42, 999_999_999).toInstant(ZoneOffset.UTC)) .build(); @@ -228,7 +228,7 @@ class DefaultWebAuthnRegistrationPageGeneratingFilterTests { .id(TestBytes.get()) .displayName("User") .build(); - ImmutableCredentialRecord credential = TestCredentialRecord.userCredential().label(label).build(); + ImmutableCredentialRecord credential = TestCredentialRecords.userCredential().label(label).build(); given(this.userEntities.findByUsername(any())).willReturn(userEntity); given(this.userCredentials.findByUserId(userEntity.getId())).willReturn(Arrays.asList(credential)); String body = bodyAsString(matchingRequest()); @@ -243,7 +243,7 @@ class DefaultWebAuthnRegistrationPageGeneratingFilterTests { .id(TestBytes.get()) .displayName("User") .build(); - ImmutableCredentialRecord credential = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credential = TestCredentialRecords.userCredential().build(); given(this.userEntities.findByUsername(any())).willReturn(userEntity); given(this.userCredentials.findByUserId(userEntity.getId())).willReturn(Arrays.asList(credential)); String body = bodyAsString(matchingRequest()); @@ -259,7 +259,7 @@ class DefaultWebAuthnRegistrationPageGeneratingFilterTests { .id(TestBytes.get()) .displayName("User") .build(); - ImmutableCredentialRecord credential = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord credential = TestCredentialRecords.userCredential().build(); given(this.userEntities.findByUsername(any())).willReturn(userEntity); given(this.userCredentials.findByUserId(userEntity.getId())).willReturn(Arrays.asList(credential)); String body = bodyAsString(matchingRequest("/foo")); diff --git a/web/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilterTests.java b/web/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilterTests.java index cca2df9385..cc8a93c7a2 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilterTests.java @@ -34,7 +34,7 @@ import org.springframework.mock.web.MockServletContext; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.webauthn.api.ImmutableCredentialRecord; import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions; -import org.springframework.security.web.webauthn.api.TestCredentialRecord; +import org.springframework.security.web.webauthn.api.TestCredentialRecords; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions; import org.springframework.security.web.webauthn.management.UserCredentialRepository; import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations; @@ -196,7 +196,7 @@ class WebAuthnRegistrationFilterTests { .createPublicKeyCredentialCreationOptions() .build(); given(this.creationOptionsRepository.load(any())).willReturn(creationOptions); - ImmutableCredentialRecord userCredential = TestCredentialRecord.userCredential().build(); + ImmutableCredentialRecord userCredential = TestCredentialRecords.userCredential().build(); given(this.operations.registerCredential(any())).willReturn(userCredential); MockHttpServletRequest request = registerCredentialRequest(REGISTRATION_REQUEST_BODY); this.filter.doFilter(request, this.response, this.chain); From 4cdc6dab217f1ce505de0956a0a5e231827707b3 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:48:28 -0600 Subject: [PATCH 011/504] Fix Formatting Issue gh-16604 --- ...SpringSecurityCoreVersionSerializableTests.java | 2 +- .../Webauthn4jRelyingPartyOperationsTests.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index 07ecb3b7db..2f4df191ac 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -239,9 +239,9 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses; import org.springframework.security.web.webauthn.api.TestBytes; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java index f60f7377d9..57c551c215 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java @@ -59,9 +59,9 @@ import org.springframework.security.web.webauthn.api.PublicKeyCredentialRpEntity import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; import org.springframework.security.web.webauthn.api.TestAuthenticatorAttestationResponses; import org.springframework.security.web.webauthn.api.TestCredentialRecords; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import static org.assertj.core.api.Assertions.assertThat; @@ -305,7 +305,8 @@ class Webauthn4jRelyingPartyOperationsTests { AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse() .clientDataJSON(new Bytes(invalidTypeClientDataJSON.getBytes(StandardCharsets.UTF_8))); - PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()) + .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); assertThatRuntimeException().isThrownBy(() -> this.rpOperations.registerCredential(registrationRequest)) @@ -327,7 +328,8 @@ class Webauthn4jRelyingPartyOperationsTests { .build(); AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()) + .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -350,7 +352,8 @@ class Webauthn4jRelyingPartyOperationsTests { .build(); AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()) + .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); @@ -375,7 +378,8 @@ class Webauthn4jRelyingPartyOperationsTests { .build(); AuthenticatorAttestationResponseBuilder responseBldr = TestAuthenticatorAttestationResponses .createAuthenticatorAttestationResponse(); - PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()).build(); + PublicKeyCredential publicKey = TestPublicKeyCredentials.createPublicKeyCredential(responseBldr.build()) + .build(); ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest( options, new RelyingPartyPublicKey(publicKey, this.label)); From 5436fd5574c89f8e16cc209ba7e4746871d18e16 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 14:15:25 -0600 Subject: [PATCH 012/504] Remove Unecessary Code --- .../Saml2AuthenticationTokenConverter.java | 15 ++++------- .../Saml2WebSsoAuthenticationFilter.java | 9 +++---- .../Saml2WebSsoAuthenticationFilterTests.java | 26 ++++++++++++++++--- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java index 6987f42464..8acc64bf97 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java @@ -16,8 +16,6 @@ package org.springframework.security.saml2.provider.service.web; -import java.util.function.Function; - import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpMethod; @@ -43,7 +41,7 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver; - private Function loader; + private Saml2AuthenticationRequestRepository authenticationRequestRepository; /** * Constructs a {@link Saml2AuthenticationTokenConverter} given a strategy for @@ -54,12 +52,13 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo public Saml2AuthenticationTokenConverter(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null"); this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver; - this.loader = new HttpSessionSaml2AuthenticationRequestRepository()::loadAuthenticationRequest; + this.authenticationRequestRepository = new HttpSessionSaml2AuthenticationRequestRepository(); } @Override public Saml2AuthenticationToken convert(HttpServletRequest request) { - AbstractSaml2AuthenticationRequest authenticationRequest = loadAuthenticationRequest(request); + AbstractSaml2AuthenticationRequest authenticationRequest = this.authenticationRequestRepository + .loadAuthenticationRequest(request); String relyingPartyRegistrationId = (authenticationRequest != null) ? authenticationRequest.getRelyingPartyRegistrationId() : null; RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationResolver.resolve(request, @@ -84,11 +83,7 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo public void setAuthenticationRequestRepository( Saml2AuthenticationRequestRepository authenticationRequestRepository) { Assert.notNull(authenticationRequestRepository, "authenticationRequestRepository cannot be null"); - this.loader = authenticationRequestRepository::loadAuthenticationRequest; - } - - private AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) { - return this.loader.apply(request); + this.authenticationRequestRepository = authenticationRequestRepository; } private String decode(HttpServletRequest request) { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java index 2e85ce082e..6c9ed2dc13 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java @@ -29,7 +29,6 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; -import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; @@ -77,9 +76,7 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce public Saml2WebSsoAuthenticationFilter(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository, String filterProcessesUrl) { this(new Saml2AuthenticationTokenConverter( - (RelyingPartyRegistrationResolver) new DefaultRelyingPartyRegistrationResolver( - relyingPartyRegistrationRepository)), - filterProcessesUrl); + new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository)), filterProcessesUrl); Assert.isTrue(filterProcessesUrl.contains("{registrationId}"), "filterProcessesUrl must contain a {registrationId} match variable"); } @@ -159,9 +156,9 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce } private void setDetails(HttpServletRequest request, Authentication authentication) { - if (AbstractAuthenticationToken.class.isAssignableFrom(authentication.getClass())) { + if (authentication instanceof AbstractAuthenticationToken token) { Object details = this.authenticationDetailsSource.buildDetails(request); - ((AbstractAuthenticationToken) authentication).setDetails(details); + token.setDetails(details); } } diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java index 98cf1765df..3ef96f8481 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java @@ -16,6 +16,7 @@ package org.springframework.security.saml2.provider.service.web.authentication; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -94,16 +95,18 @@ public class Saml2WebSsoAuthenticationFilterTests { @Test public void requiresAuthenticationWhenHappyPathThenReturnsTrue() { - assertThat(this.filter.requiresAuthentication(this.request, this.response)).isTrue(); + RequiresAuthenticationExposingFilter filter = new RequiresAuthenticationExposingFilter(this.repository); + assertThat(filter.requiresAuthentication(this.request, this.response)).isTrue(); } @Test public void requiresAuthenticationWhenCustomProcessingUrlThenReturnsTrue() { - this.filter = new Saml2WebSsoAuthenticationFilter(this.repository, "/some/other/path/{registrationId}"); + RequiresAuthenticationExposingFilter filter = new RequiresAuthenticationExposingFilter(this.repository, + "/some/other/path/{registrationId}"); this.request.setRequestURI("/some/other/path/idp-registration-id"); this.request.setPathInfo("/some/other/path/idp-registration-id"); this.request.setParameter(Saml2ParameterNames.SAML_RESPONSE, "xml-data-goes-here"); - assertThat(this.filter.requiresAuthentication(this.request, this.response)).isTrue(); + assertThat(filter.requiresAuthentication(this.request, this.response)).isTrue(); } @Test @@ -212,4 +215,21 @@ public class Saml2WebSsoAuthenticationFilterTests { verify(this.repository).findByRegistrationId("registration-id"); } + static final class RequiresAuthenticationExposingFilter extends Saml2WebSsoAuthenticationFilter { + + RequiresAuthenticationExposingFilter(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) { + super(relyingPartyRegistrationRepository); + } + + RequiresAuthenticationExposingFilter(RelyingPartyRegistrationRepository registrations, String url) { + super(registrations, url); + } + + @Override + protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { + return super.requiresAuthentication(request, response); + } + + } + } From 67c21de1cfdf3b4ecaaad1f7fd6b59887b47f33d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:32:04 -0600 Subject: [PATCH 013/504] Support Continue Filter Chain When No Relying Party Closes gh-16000 --- .../modules/ROOT/pages/migration-7/saml2.adoc | 60 +++++++++++++++++++ .../Saml2WebSsoAuthenticationFilter.java | 21 +++++++ .../Saml2WebSsoAuthenticationFilterTests.java | 28 ++++++++- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 docs/modules/ROOT/pages/migration-7/saml2.adoc diff --git a/docs/modules/ROOT/pages/migration-7/saml2.adoc b/docs/modules/ROOT/pages/migration-7/saml2.adoc new file mode 100644 index 0000000000..9a8cb60080 --- /dev/null +++ b/docs/modules/ROOT/pages/migration-7/saml2.adoc @@ -0,0 +1,60 @@ += 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"] +---- + +---- +====== diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java index 6c9ed2dc13..9c584a7501 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilter.java @@ -54,6 +54,8 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce private Saml2AuthenticationRequestRepository authenticationRequestRepository = new HttpSessionSaml2AuthenticationRequestRepository(); + private boolean continueChainWhenNoRelyingPartyRegistrationFound = false; + /** * Creates a {@code Saml2WebSsoAuthenticationFilter} authentication filter that is * configured to use the {@link #DEFAULT_FILTER_PROCESSES_URI} processing URL @@ -94,6 +96,7 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce this.authenticationConverter = authenticationConverter; setAllowSessionCreation(true); setSessionAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy()); + setAuthenticationConverter(authenticationConverter); } /** @@ -110,6 +113,7 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce this.authenticationConverter = authenticationConverter; setAllowSessionCreation(true); setSessionAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy()); + setAuthenticationConverter(authenticationConverter); } @Override @@ -122,6 +126,9 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce throws AuthenticationException { Authentication authentication = this.authenticationConverter.convert(request); if (authentication == null) { + if (this.continueChainWhenNoRelyingPartyRegistrationFound) { + return null; + } Saml2Error saml2Error = new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND, "No relying party registration found"); throw new Saml2AuthenticationException(saml2Error); @@ -156,10 +163,24 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce } private void setDetails(HttpServletRequest request, Authentication authentication) { + if (authentication.getDetails() != null) { + return; + } if (authentication instanceof AbstractAuthenticationToken token) { Object details = this.authenticationDetailsSource.buildDetails(request); token.setDetails(details); } } + /** + * Indicate whether to continue with the rest of the filter chain in the event that no + * relying party registration is found. This is {@code false} by default, meaning that + * it will throw an exception. + * @param continueChain whether to continue + * @since 6.5 + */ + public void setContinueChainWhenNoRelyingPartyRegistrationFound(boolean continueChain) { + this.continueChainWhenNoRelyingPartyRegistrationFound = continueChain; + } + } diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java index 3ef96f8481..9e4b4d3269 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2WebSsoAuthenticationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.security.saml2.provider.service.web.authentication; +import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.BeforeEach; @@ -121,6 +122,31 @@ public class Saml2WebSsoAuthenticationFilterTests { .withMessage("No relying party registration found"); } + @Test + public void doFilterWhenContinueChainRegistrationIdDoesNotExistThenContinues() throws Exception { + given(this.repository.findByRegistrationId("non-existent-id")).willReturn(null); + this.filter = new Saml2WebSsoAuthenticationFilter(this.repository, "/some/other/path/{registrationId}"); + this.filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true); + this.request.setRequestURI("/some/other/path/non-existent-id"); + this.request.setPathInfo("/some/other/path/non-existent-id"); + FilterChain chain = mock(FilterChain.class); + this.filter.doFilter(this.request, this.response, chain); + verify(chain).doFilter(this.request, this.response); + } + + @Test + public void doFilterWhenContinueChainNoSamlResponseThenContinues() throws Exception { + given(this.repository.findByRegistrationId("id")).willReturn(TestRelyingPartyRegistrations.full().build()); + this.filter = new Saml2WebSsoAuthenticationFilter(this.repository, "/some/other/path/{registrationId}"); + this.filter.setContinueChainWhenNoRelyingPartyRegistrationFound(true); + this.request.setRequestURI("/some/other/path/id"); + this.request.setPathInfo("/some/other/path/id"); + this.request.removeParameter(Saml2ParameterNames.SAML_RESPONSE); + FilterChain chain = mock(FilterChain.class); + this.filter.doFilter(this.request, this.response, chain); + verify(chain).doFilter(this.request, this.response); + } + @Test public void attemptAuthenticationWhenSavedAuthnRequestThenRemovesAuthnRequest() { Saml2AuthenticationRequestRepository authenticationRequestRepository = mock( From 8cbe02e3aae459f1f530beac43e06665b7be7d50 Mon Sep 17 00:00:00 2001 From: chu3la Date: Sat, 1 Mar 2025 16:37:38 +0000 Subject: [PATCH 014/504] Update WebAuthn Test Objects Class Names Closes gh-16604 Signed-off-by: chu3la --- ...HttpSecurity.java => TestHttpSecurities.java} | 4 ++-- .../web/configurers/DefaultFiltersTests.java | 4 ++-- .../NamespaceHttpCustomFilterTests.java | 8 ++++---- .../SecurityContextConfigurerTests.java | 4 ++-- ...tingWebInvocationPrivilegeEvaluatorTests.java | 16 ++++++++-------- ...=> TestWebInvocationPrivilegeEvaluators.java} | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) rename config/src/test/java/org/springframework/security/config/annotation/web/builders/{TestHttpSecurity.java => TestHttpSecurities.java} (95%) rename web/src/test/java/org/springframework/security/web/access/{TestWebInvocationPrivilegeEvaluator.java => TestWebInvocationPrivilegeEvaluators.java} (94%) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurity.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurities.java similarity index 95% rename from config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurity.java rename to config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurities.java index d55d978cab..b123ce25cd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurity.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/TestHttpSecurities.java @@ -21,9 +21,9 @@ import java.util.List; import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer; import org.springframework.test.util.ReflectionTestUtils; -public final class TestHttpSecurity { +public final class TestHttpSecurities { - private TestHttpSecurity() { + private TestHttpSecurities() { } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java index d551a2e305..e5a3b3cc0b 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java @@ -31,7 +31,7 @@ import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.TestHttpSecurity; +import org.springframework.security.config.annotation.web.builders.TestHttpSecurities; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.test.SpringTestContext; @@ -169,7 +169,7 @@ public class DefaultFiltersTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - TestHttpSecurity.disableDefaults(http); + TestHttpSecurities.disableDefaults(http); http.formLogin(); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java index 19caf278ef..36920cd85a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java @@ -32,7 +32,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.TestHttpSecurity; +import org.springframework.security.config.annotation.web.builders.TestHttpSecurities; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; @@ -140,7 +140,7 @@ public class NamespaceHttpCustomFilterTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off - TestHttpSecurity.disableDefaults(http); + TestHttpSecurities.disableDefaults(http); http // this works so long as the CustomFilter extends one of the standard filters // if not, use addFilterBefore or addFilterAfter @@ -158,7 +158,7 @@ public class NamespaceHttpCustomFilterTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off - TestHttpSecurity.disableDefaults(http); + TestHttpSecurities.disableDefaults(http); http .addFilterAt(new OtherCustomFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); @@ -179,7 +179,7 @@ public class NamespaceHttpCustomFilterTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off - TestHttpSecurity.disableDefaults(http); + TestHttpSecurities.disableDefaults(http); http .authorizeRequests() .anyRequest().hasRole("USER") diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java index 5de55764f4..31c6fbfc66 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java @@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.TestDeferredSecurityContext; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.TestHttpSecurity; +import org.springframework.security.config.annotation.web.builders.TestHttpSecurities; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; @@ -199,7 +199,7 @@ public class SecurityContextConfigurerTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - TestHttpSecurity.disableDefaults(http); + TestHttpSecurities.disableDefaults(http); // @formatter:off http .addFilter(new WebAsyncManagerIntegrationFilter()) diff --git a/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java b/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java index b2417ec3aa..8847cfa93e 100644 --- a/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java +++ b/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java @@ -75,7 +75,7 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { @Test void isAllowedWhenNotMatchThenAllowed() { RequestMatcherEntry> notMatch = entry(this.alwaysDeny, - TestWebInvocationPrivilegeEvaluator.alwaysAllow()); + TestWebInvocationPrivilegeEvaluators.alwaysAllow()); WebInvocationPrivilegeEvaluator delegating = evaluator(notMatch); assertThat(delegating.isAllowed(this.uri, this.authentication)).isTrue(); verify(notMatch.getRequestMatcher()).matches(any()); @@ -96,9 +96,9 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { @Test void isAllowedWhenNotMatchThenMatchThenOnlySecondDelegateInvoked() { RequestMatcherEntry> notMatchDelegate = entry(this.alwaysDeny, - TestWebInvocationPrivilegeEvaluator.alwaysAllow()); + TestWebInvocationPrivilegeEvaluators.alwaysAllow()); RequestMatcherEntry> matchDelegate = entry(this.alwaysMatch, - TestWebInvocationPrivilegeEvaluator.alwaysAllow()); + TestWebInvocationPrivilegeEvaluators.alwaysAllow()); RequestMatcherEntry> spyNotMatchDelegate = spy(notMatchDelegate); RequestMatcherEntry> spyMatchDelegate = spy(matchDelegate); @@ -120,8 +120,8 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { @Test void isAllowedWhenFirstDelegateDenyThenDoNotInvokeOthers() { - WebInvocationPrivilegeEvaluator deny = TestWebInvocationPrivilegeEvaluator.alwaysDeny(); - WebInvocationPrivilegeEvaluator allow = TestWebInvocationPrivilegeEvaluator.alwaysAllow(); + WebInvocationPrivilegeEvaluator deny = TestWebInvocationPrivilegeEvaluators.alwaysDeny(); + WebInvocationPrivilegeEvaluator allow = TestWebInvocationPrivilegeEvaluators.alwaysAllow(); WebInvocationPrivilegeEvaluator spyDeny = spy(deny); WebInvocationPrivilegeEvaluator spyAllow = spy(allow); RequestMatcherEntry> delegate = entry(this.alwaysMatch, spyDeny, @@ -136,7 +136,7 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { @Test void isAllowedWhenDifferentArgumentsThenCallSpecificIsAllowedInDelegate() { - WebInvocationPrivilegeEvaluator deny = TestWebInvocationPrivilegeEvaluator.alwaysDeny(); + WebInvocationPrivilegeEvaluator deny = TestWebInvocationPrivilegeEvaluators.alwaysDeny(); WebInvocationPrivilegeEvaluator spyDeny = spy(deny); RequestMatcherEntry> delegate = entry(this.alwaysMatch, spyDeny); @@ -197,11 +197,11 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { } private RequestMatcherEntry> allow(RequestMatcher requestMatcher) { - return entry(requestMatcher, TestWebInvocationPrivilegeEvaluator.alwaysAllow()); + return entry(requestMatcher, TestWebInvocationPrivilegeEvaluators.alwaysAllow()); } private RequestMatcherEntry> deny(RequestMatcher requestMatcher) { - return entry(requestMatcher, TestWebInvocationPrivilegeEvaluator.alwaysDeny()); + return entry(requestMatcher, TestWebInvocationPrivilegeEvaluators.alwaysDeny()); } private RequestMatcherEntry> entry(RequestMatcher requestMatcher, diff --git a/web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluator.java b/web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluators.java similarity index 94% rename from web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluator.java rename to web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluators.java index 54ab666cd5..9ee7278a1c 100644 --- a/web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluator.java +++ b/web/src/test/java/org/springframework/security/web/access/TestWebInvocationPrivilegeEvaluators.java @@ -18,13 +18,13 @@ package org.springframework.security.web.access; import org.springframework.security.core.Authentication; -public final class TestWebInvocationPrivilegeEvaluator { +public final class TestWebInvocationPrivilegeEvaluators { private static final AlwaysAllowWebInvocationPrivilegeEvaluator ALWAYS_ALLOW = new AlwaysAllowWebInvocationPrivilegeEvaluator(); private static final AlwaysDenyWebInvocationPrivilegeEvaluator ALWAYS_DENY = new AlwaysDenyWebInvocationPrivilegeEvaluator(); - private TestWebInvocationPrivilegeEvaluator() { + private TestWebInvocationPrivilegeEvaluators() { } public static WebInvocationPrivilegeEvaluator alwaysAllow() { From a283700ef8182ebfc480a2a047b79f25e0768b9e Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:10:11 -0600 Subject: [PATCH 015/504] Add CacheSaml2AuthenticationRequestRepository Closes gh-14793 --- .../saml2/login/authentication-requests.adoc | 40 ++++++++ ...eSaml2AuthenticationRequestRepository.java | 84 +++++++++++++++++ ...2AuthenticationRequestRepositoryTests.java | 91 +++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepository.java create mode 100644 saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepositoryTests.java diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc index 2798eea564..29505f3024 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc @@ -83,6 +83,46 @@ open fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository ---- ====== +=== Caching the `` by the Relay State + +If you don't want to use the session to store the ``, you can also store it in a distributed cache. +This can be helpful if you are trying to use `SameSite=Strict` and are losing the authentication request in the redirect from the Identity Provider. + +[NOTE] +===== +It's important to remember that there are security benefits to storing it in the session. +One such benefit is the natural login fixation defense it provides. +For example, if an application looks the authentication request up from the session, then even if an attacker provides their own SAML response to a victim, the login will fail. + +On the other hand, if we trust the InResponseTo or RelayState to retrieve the authentication request, then there's no way to know if the SAML response was requested by that handshake. +===== + +To help with this, Spring Security has `CacheSaml2AuthenticationRequestRepository`, which you can publish as a bean for the filter chain to pick up: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +Saml2AuthenticationRequestRepository authenticationRequestRepository() { + return new CacheSaml2AuthenticationRequestRepository(); +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository<*> { + return CacheSaml2AuthenticationRequestRepository() +} +---- +====== + + [[servlet-saml2login-sp-initiated-factory-signing]] == Changing How the `` Gets Sent diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepository.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepository.java new file mode 100644 index 0000000000..d5813548bd --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepository.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.web; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCache; +import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; +import org.springframework.util.Assert; + +/** + * A cache-based {@link Saml2AuthenticationRequestRepository}. This can be handy when you + * are dropping requests due to using SameSite=Strict and the previous session is lost. + * + *

+ * On the other hand, this presents a tradeoff where the application can only tell that + * the given authentication request was created by this application, but cannot guarantee + * that it was for the user trying to log in. Please see the reference for details. + * + * @author Josh Cummings + * @since 6.5 + */ +public final class CacheSaml2AuthenticationRequestRepository + implements Saml2AuthenticationRequestRepository { + + private Cache cache = new ConcurrentMapCache("authentication-requests"); + + @Override + public AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) { + String relayState = request.getParameter(Saml2ParameterNames.RELAY_STATE); + Assert.notNull(relayState, "relayState must not be null"); + return this.cache.get(relayState, AbstractSaml2AuthenticationRequest.class); + } + + @Override + public void saveAuthenticationRequest(AbstractSaml2AuthenticationRequest authenticationRequest, + HttpServletRequest request, HttpServletResponse response) { + String relayState = request.getParameter(Saml2ParameterNames.RELAY_STATE); + Assert.notNull(relayState, "relayState must not be null"); + this.cache.put(relayState, authenticationRequest); + } + + @Override + public AbstractSaml2AuthenticationRequest removeAuthenticationRequest(HttpServletRequest request, + HttpServletResponse response) { + String relayState = request.getParameter(Saml2ParameterNames.RELAY_STATE); + Assert.notNull(relayState, "relayState must not be null"); + AbstractSaml2AuthenticationRequest authenticationRequest = this.cache.get(relayState, + AbstractSaml2AuthenticationRequest.class); + if (authenticationRequest == null) { + return null; + } + this.cache.evict(relayState); + return authenticationRequest; + } + + /** + * Use this {@link Cache} instance. The default is an in-memory cache, which means it + * won't work in a clustered environment. Instead, replace it here with a distributed + * cache. + * @param cache the {@link Cache} instance to use + */ + public void setCache(Cache cache) { + this.cache = cache; + } + +} diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepositoryTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepositoryTests.java new file mode 100644 index 0000000000..3bd35652f4 --- /dev/null +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/CacheSaml2AuthenticationRequestRepositoryTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.web; + +import org.junit.jupiter.api.Test; + +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCache; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link CacheSaml2AuthenticationRequestRepository} + */ +class CacheSaml2AuthenticationRequestRepositoryTests { + + CacheSaml2AuthenticationRequestRepository repository = new CacheSaml2AuthenticationRequestRepository(); + + @Test + void loadAuthenticationRequestWhenCachedThenReturns() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter(Saml2ParameterNames.RELAY_STATE, "test"); + Saml2PostAuthenticationRequest authenticationRequest = TestSaml2PostAuthenticationRequests.create(); + this.repository.saveAuthenticationRequest(authenticationRequest, request, null); + assertThat(this.repository.loadAuthenticationRequest(request)).isEqualTo(authenticationRequest); + this.repository.removeAuthenticationRequest(request, null); + assertThat(this.repository.loadAuthenticationRequest(request)).isNull(); + } + + @Test + void loadAuthenticationRequestWhenNoRelayStateThenException() { + MockHttpServletRequest request = new MockHttpServletRequest(); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> this.repository.loadAuthenticationRequest(request)); + } + + @Test + void saveAuthenticationRequestWhenNoRelayStateThenException() { + MockHttpServletRequest request = new MockHttpServletRequest(); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> this.repository.saveAuthenticationRequest(null, request, null)); + } + + @Test + void removeAuthenticationRequestWhenNoRelayStateThenException() { + MockHttpServletRequest request = new MockHttpServletRequest(); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> this.repository.removeAuthenticationRequest(request, null)); + } + + @Test + void repositoryWhenCustomCacheThenUses() { + CacheSaml2AuthenticationRequestRepository repository = new CacheSaml2AuthenticationRequestRepository(); + Cache cache = spy(new ConcurrentMapCache("requests")); + repository.setCache(cache); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setParameter(Saml2ParameterNames.RELAY_STATE, "test"); + Saml2PostAuthenticationRequest authenticationRequest = TestSaml2PostAuthenticationRequests.create(); + repository.saveAuthenticationRequest(authenticationRequest, request, null); + verify(cache).put(eq("test"), any()); + repository.loadAuthenticationRequest(request); + verify(cache).get("test", AbstractSaml2AuthenticationRequest.class); + repository.removeAuthenticationRequest(request, null); + verify(cache).evict("test"); + } + +} From 1eff17677628af5d0779ae9fd39e24bd5c30d310 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 00:05:45 +0000 Subject: [PATCH 016/504] Bump spring-io/spring-doc-actions from 0.0.19 to 0.0.20 Bumps [spring-io/spring-doc-actions](https://github.com/spring-io/spring-doc-actions) from 0.0.19 to 0.0.20. - [Commits](https://github.com/spring-io/spring-doc-actions/compare/c2038265125ec6f305a4a041d892ee44c156a754...e28269199d1d27975cf7f65e16d6095c555b3cd0) --- updated-dependencies: - dependency-name: spring-io/spring-doc-actions dependency-version: 0.0.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-antora-ui-spring.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-antora-ui-spring.yml b/.github/workflows/update-antora-ui-spring.yml index b6c25281cb..f1309ed301 100644 --- a/.github/workflows/update-antora-ui-spring.yml +++ b/.github/workflows/update-antora-ui-spring.yml @@ -18,7 +18,7 @@ jobs: matrix: branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ] steps: - - uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754 + - uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 name: Update with: docs-branch: ${{ matrix.branch }} @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest name: Update on docs-build steps: - - uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754 + - uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 name: Update with: docs-branch: 'docs-build' From f3c8262a00def163be4f5c4ccb0beb1ad6bda948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 00:11:26 +0000 Subject: [PATCH 017/504] Bump spring-io/spring-doc-actions from 0.0.19 to 0.0.20 Bumps [spring-io/spring-doc-actions](https://github.com/spring-io/spring-doc-actions) from 0.0.19 to 0.0.20. - [Commits](https://github.com/spring-io/spring-doc-actions/compare/c2038265125ec6f305a4a041d892ee44c156a754...e28269199d1d27975cf7f65e16d6095c555b3cd0) --- updated-dependencies: - dependency-name: spring-io/spring-doc-actions dependency-version: 0.0.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/update-antora-ui-spring.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-antora-ui-spring.yml b/.github/workflows/update-antora-ui-spring.yml index b6c25281cb..f1309ed301 100644 --- a/.github/workflows/update-antora-ui-spring.yml +++ b/.github/workflows/update-antora-ui-spring.yml @@ -18,7 +18,7 @@ jobs: matrix: branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ] steps: - - uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754 + - uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 name: Update with: docs-branch: ${{ matrix.branch }} @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest name: Update on docs-build steps: - - uses: spring-io/spring-doc-actions/update-antora-spring-ui@c2038265125ec6f305a4a041d892ee44c156a754 + - uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0 name: Update with: docs-branch: 'docs-build' From a081402383a50260128d029dccdc5eacd79d667e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:44:28 +0000 Subject: [PATCH 018/504] Bump org.hibernate.orm:hibernate-core from 6.6.12.Final to 6.6.13.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.12.Final to 6.6.13.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.13/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.12...6.6.13) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.13.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b68730d2d..d4d15b58d7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.12.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From ff29c1b5475c074e78620d6748cfc39bc40b242d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:47:50 +0000 Subject: [PATCH 019/504] Bump org.seleniumhq.selenium:selenium-java from 4.30.0 to 4.31.0 Bumps [org.seleniumhq.selenium:selenium-java](https://github.com/SeleniumHQ/selenium) from 4.30.0 to 4.31.0. - [Release notes](https://github.com/SeleniumHQ/selenium/releases) - [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-4.30.0...selenium-4.31.0) --- updated-dependencies: - dependency-name: org.seleniumhq.selenium:selenium-java dependency-version: 4.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3c8b5eccd4..b8ce6a32ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-opensaml-opensaml5-saml-api = { module = "org.opensaml:opensaml-saml-api", v org-opensaml-opensaml5-saml-impl = { module = "org.opensaml:opensaml-saml-impl", version.ref = "org-opensaml5" } org-python-jython = { module = "org.python:jython", version = "2.5.3" } org-seleniumhq-selenium-htmlunit-driver = "org.seleniumhq.selenium:htmlunit3-driver:4.30.0" -org-seleniumhq-selenium-selenium-java = "org.seleniumhq.selenium:selenium-java:4.30.0" +org-seleniumhq-selenium-selenium-java = "org.seleniumhq.selenium:selenium-java:4.31.0" org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-support:3.141.59" org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" From 0a2b9d4978dfdc9027beb4d3d37b8f16ab3d4798 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:48:06 +0000 Subject: [PATCH 020/504] Bump org.hibernate.orm:hibernate-core from 6.6.12.Final to 6.6.13.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.12.Final to 6.6.13.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.13/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.12...6.6.13) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.13.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8ce6a32ac..7dfd3dbba8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.12.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 21a85e35209569220bdde307eaa55d8d595ea2e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:48:16 +0000 Subject: [PATCH 021/504] Bump org.mockito:mockito-bom from 5.16.1 to 5.17.0 Bumps [org.mockito:mockito-bom](https://github.com/mockito/mockito) from 5.16.1 to 5.17.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-bom dependency-version: 5.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7dfd3dbba8..38b7ee6a19 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.10.1" -org-mockito = "5.16.1" +org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" org-springframework = "6.2.5" From 9c073dbcded6ff8ac702f761be15b66d10e75db2 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:20:22 -0400 Subject: [PATCH 022/504] Add AuthenticationEntryPoint for DPoP Issue gh-16574 Closes gh-16900 --- .../DPoPAuthenticationConfigurer.java | 53 ++++++++++++++++++- .../DPoPAuthenticationConfigurerTests.java | 13 +++-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java index acbe822191..b433602e5a 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java @@ -17,11 +17,14 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -29,18 +32,21 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationProvider; import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationFilter; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; -import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.CollectionUtils; @@ -102,7 +108,7 @@ final class DPoPAuthenticationConfigurer> private AuthenticationFailureHandler getAuthenticationFailureHandler() { if (this.authenticationFailureHandler == null) { this.authenticationFailureHandler = new AuthenticationEntryPointFailureHandler( - new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)); + new DPoPAuthenticationEntryPoint()); } return this.authenticationFailureHandler; } @@ -161,4 +167,47 @@ final class DPoPAuthenticationConfigurer> } + private static final class DPoPAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authenticationException) { + Map parameters = new LinkedHashMap<>(); + if (authenticationException instanceof OAuth2AuthenticationException oauth2AuthenticationException) { + OAuth2Error error = oauth2AuthenticationException.getError(); + parameters.put(OAuth2ParameterNames.ERROR, error.getErrorCode()); + if (StringUtils.hasText(error.getDescription())) { + parameters.put(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription()); + } + if (StringUtils.hasText(error.getUri())) { + parameters.put(OAuth2ParameterNames.ERROR_URI, error.getUri()); + } + } + parameters.put("algs", + JwsAlgorithms.RS256 + " " + JwsAlgorithms.RS384 + " " + JwsAlgorithms.RS512 + " " + + JwsAlgorithms.PS256 + " " + JwsAlgorithms.PS384 + " " + JwsAlgorithms.PS512 + " " + + JwsAlgorithms.ES256 + " " + JwsAlgorithms.ES384 + " " + JwsAlgorithms.ES512); + String wwwAuthenticate = toWWWAuthenticateHeader(parameters); + response.addHeader(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticate); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + } + + private static String toWWWAuthenticateHeader(Map parameters) { + StringBuilder wwwAuthenticate = new StringBuilder(); + wwwAuthenticate.append(OAuth2AccessToken.TokenType.DPOP.getValue()); + if (!parameters.isEmpty()) { + wwwAuthenticate.append(" "); + int i = 0; + for (Map.Entry entry : parameters.entrySet()) { + wwwAuthenticate.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\""); + if (i++ != parameters.size() - 1) { + wwwAuthenticate.append(", "); + } + } + } + return wwwAuthenticate.toString(); + } + + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index 0011728624..d908607a1f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -70,6 +70,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** @@ -120,7 +121,9 @@ public class DPoPAuthenticationConfigurerTests { .header(HttpHeaders.AUTHORIZATION, "DPoP " + accessToken) .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken) .header("DPoP", dPoPProof)) - .andExpect(status().isUnauthorized()); + .andExpect(status().isUnauthorized()) + .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, + "DPoP error=\"invalid_request\", error_description=\"Found multiple Authorization headers.\", algs=\"RS256 RS384 RS512 PS256 PS384 PS512 ES256 ES384 ES512\"")); // @formatter:on } @@ -134,7 +137,9 @@ public class DPoPAuthenticationConfigurerTests { this.mvc.perform(get("/resource1") .header(HttpHeaders.AUTHORIZATION, "DPoP " + accessToken + " m a l f o r m e d ") .header("DPoP", dPoPProof)) - .andExpect(status().isUnauthorized()); + .andExpect(status().isUnauthorized()) + .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, + "DPoP error=\"invalid_token\", error_description=\"DPoP access token is malformed.\", algs=\"RS256 RS384 RS512 PS256 PS384 PS512 ES256 ES384 ES512\"")); // @formatter:on } @@ -149,7 +154,9 @@ public class DPoPAuthenticationConfigurerTests { .header(HttpHeaders.AUTHORIZATION, "DPoP " + accessToken) .header("DPoP", dPoPProof) .header("DPoP", dPoPProof)) - .andExpect(status().isUnauthorized()); + .andExpect(status().isUnauthorized()) + .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, + "DPoP error=\"invalid_request\", error_description=\"DPoP proof is missing or invalid.\", algs=\"RS256 RS384 RS512 PS256 PS384 PS512 ES256 ES384 ES512\"")); // @formatter:on } From da94fbe4315556e8541d194df8a815817698fe9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Tue, 5 Nov 2024 02:30:03 -0600 Subject: [PATCH 023/504] Evaluate URI query parameter only if enabled Issue gh-16038 --- .../OAuth2ResourceServerConfigurerTests.java | 3 +++ ...verBeanDefinitionParserTests-JwkSetUri.xml | 7 ++++- .../web/DefaultBearerTokenResolver.java | 26 ++++++++----------- ...verBearerTokenAuthenticationConverter.java | 18 ++++++------- .../web/DefaultBearerTokenResolverTests.java | 23 ++++++++++++++++ ...arerTokenAuthenticationConverterTests.java | 10 +++++++ 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index cb2ba0e137..493a7f0eaf 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1560,12 +1560,15 @@ public class OAuth2ResourceServerConfigurerTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off + DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver(); + defaultBearerTokenResolver.setAllowUriQueryParameter(true); http .authorizeRequests() .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") .anyRequest().authenticated() .and() .oauth2ResourceServer() + .bearerTokenResolver(defaultBearerTokenResolver) .jwt() .jwkSetUri(this.jwkSetUri); return http.build(); diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml index 3f81363d27..aac12989e9 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-JwkSetUri.xml @@ -25,10 +25,15 @@ + + + + - + diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java index d238e87017..96aa1be570 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java @@ -53,8 +53,8 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { @Override public String resolve(final HttpServletRequest request) { final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); - final String parameterToken = isParameterTokenSupportedForRequest(request) - ? resolveFromRequestParameters(request) : null; + final String parameterToken = resolveFromRequestParameters(request); + if (authorizationHeaderToken != null) { if (parameterToken != null) { BearerTokenError error = BearerTokenErrors @@ -63,15 +63,12 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { } return authorizationHeaderToken; } - if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { - if (!StringUtils.hasText(parameterToken)) { - BearerTokenError error = BearerTokenErrors - .invalidRequest("The requested token parameter is an empty string"); - throw new OAuth2AuthenticationException(error); - } - return parameterToken; + if (parameterToken != null && parameterToken.isBlank()) { + BearerTokenError error = BearerTokenErrors + .invalidRequest("The requested token parameter is an empty string"); + throw new OAuth2AuthenticationException(error); } - return null; + return parameterToken; } /** @@ -122,7 +119,10 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { return matcher.group("token"); } - private static String resolveFromRequestParameters(HttpServletRequest request) { + private String resolveFromRequestParameters(HttpServletRequest request) { + if (!isParameterTokenEnabledForRequest(request)) { + return null; + } String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME); if (values == null || values.length == 0) { return null; @@ -134,10 +134,6 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { throw new OAuth2AuthenticationException(error); } - private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) { - return isFormEncodedRequest(request) || isGetRequest(request); - } - private static boolean isGetRequest(HttpServletRequest request) { return HttpMethod.GET.name().equals(request.getMethod()); } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index bd07c59b74..ec7675acd0 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -77,18 +77,18 @@ public class ServerBearerTokenAuthenticationConverter implements ServerAuthentic } return authorizationHeaderToken; } - if (parameterToken != null && isParameterTokenSupportedForRequest(request)) { - if (!StringUtils.hasText(parameterToken)) { - BearerTokenError error = BearerTokenErrors - .invalidRequest("The requested token parameter is an empty string"); - throw new OAuth2AuthenticationException(error); - } - return parameterToken; + if (parameterToken != null && !StringUtils.hasText(parameterToken)) { + BearerTokenError error = BearerTokenErrors + .invalidRequest("The requested token parameter is an empty string"); + throw new OAuth2AuthenticationException(error); } - return null; + return parameterToken; } - private static String resolveAccessTokenFromRequest(ServerHttpRequest request) { + private String resolveAccessTokenFromRequest(ServerHttpRequest request) { + if (!isParameterTokenSupportedForRequest(request)) { + return null; + } List parameterTokens = request.getQueryParams().get("access_token"); if (CollectionUtils.isEmpty(parameterTokens)) { return null; diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java index f04fb69a3d..6c62d7c27f 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java @@ -110,6 +110,7 @@ public class DefaultBearerTokenResolverTests { @Test public void resolveWhenValidHeaderIsPresentTogetherWithFormParameterThenAuthenticationExceptionIsThrown() { + this.resolver.setAllowFormEncodedBodyParameter(true); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", "Bearer " + TEST_TOKEN); request.setMethod("POST"); @@ -121,6 +122,7 @@ public class DefaultBearerTokenResolverTests { @Test public void resolveWhenValidHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() { + this.resolver.setAllowUriQueryParameter(true); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", "Bearer " + TEST_TOKEN); request.setMethod("GET"); @@ -133,6 +135,7 @@ public class DefaultBearerTokenResolverTests { // gh-10326 @Test public void resolveWhenRequestContainsTwoAccessTokenQueryParametersThenAuthenticationExceptionIsThrown() { + this.resolver.setAllowUriQueryParameter(true); MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("GET"); request.addParameter("access_token", "token1", "token2"); @@ -143,6 +146,7 @@ public class DefaultBearerTokenResolverTests { // gh-10326 @Test public void resolveWhenRequestContainsTwoAccessTokenFormParametersThenAuthenticationExceptionIsThrown() { + this.resolver.setAllowFormEncodedBodyParameter(true); MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("POST"); request.setContentType("application/x-www-form-urlencoded"); @@ -261,6 +265,25 @@ public class DefaultBearerTokenResolverTests { assertThat(this.resolver.resolve(request)).isNull(); } + // gh-16038 + @Test + void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("application/x-www-form-urlencoded"); + request.addParameter("access_token", "token1", "token2"); + assertThat(this.resolver.resolve(request)).isNull(); + } + + // gh-16038 + @Test + void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + request.addParameter("access_token", "token1", "token2"); + assertThat(this.resolver.resolve(request)).isNull(); + } + @Test public void resolveWhenQueryParameterIsPresentAndEmptyStringThenTokenIsNotResolved() { this.resolver.setAllowUriQueryParameter(true); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index 1f4b17697f..3e47401824 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -157,6 +157,7 @@ public class ServerBearerTokenAuthenticationConverterTests { @Test public void resolveWhenValidHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() { // @formatter:off + this.converter.setAllowUriQueryParameter(true); MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") .queryParam("access_token", TEST_TOKEN) .header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN); @@ -205,6 +206,7 @@ public class ServerBearerTokenAuthenticationConverterTests { @Test void resolveWhenQueryParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { + this.converter.setAllowUriQueryParameter(true); MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") .queryParam("access_token", TEST_TOKEN, TEST_TOKEN); assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) @@ -217,6 +219,14 @@ public class ServerBearerTokenAuthenticationConverterTests { } + // gh-16038 + @Test + void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { + MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") + .queryParam("access_token", TEST_TOKEN, TEST_TOKEN); + assertThat(convertToToken(request)).isNull(); + } + private BearerTokenAuthenticationToken convertToToken(MockServerHttpRequest.BaseBuilder request) { return convertToToken(request.build()); } From 3c0fef59b547359ac3e5824c6b56694c3cb7b8dd Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:12:44 -0600 Subject: [PATCH 024/504] Polish gh-16039 Closes gh-16038 --- .../OAuth2ResourceServerConfigurerTests.java | 2 +- .../web/DefaultBearerTokenResolver.java | 113 ++++++++++-------- ...verBearerTokenAuthenticationConverter.java | 2 +- .../web/DefaultBearerTokenResolverTests.java | 19 ++- ...arerTokenAuthenticationConverterTests.java | 2 +- 5 files changed, 80 insertions(+), 58 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 493a7f0eaf..903df193d9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java index 96aa1be570..f00305843a 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java @@ -52,23 +52,77 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { @Override public String resolve(final HttpServletRequest request) { - final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); - final String parameterToken = resolveFromRequestParameters(request); + // @formatter:off + return resolveToken( + resolveFromAuthorizationHeader(request), + resolveAccessTokenFromQueryString(request), + resolveAccessTokenFromBody(request) + ); + // @formatter:on + } - if (authorizationHeaderToken != null) { - if (parameterToken != null) { + private static String resolveToken(String... accessTokens) { + if (accessTokens == null || accessTokens.length == 0) { + return null; + } + + String accessToken = null; + for (String token : accessTokens) { + if (accessToken == null) { + accessToken = token; + } + else if (token != null) { BearerTokenError error = BearerTokenErrors .invalidRequest("Found multiple bearer tokens in the request"); throw new OAuth2AuthenticationException(error); } - return authorizationHeaderToken; } - if (parameterToken != null && parameterToken.isBlank()) { + + if (accessToken != null && accessToken.isBlank()) { BearerTokenError error = BearerTokenErrors .invalidRequest("The requested token parameter is an empty string"); throw new OAuth2AuthenticationException(error); } - return parameterToken; + + return accessToken; + } + + private String resolveFromAuthorizationHeader(HttpServletRequest request) { + String authorization = request.getHeader(this.bearerTokenHeaderName); + if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { + return null; + } + + Matcher matcher = authorizationPattern.matcher(authorization); + if (!matcher.matches()) { + BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); + throw new OAuth2AuthenticationException(error); + } + + return matcher.group("token"); + } + + private String resolveAccessTokenFromQueryString(HttpServletRequest request) { + if (!this.allowUriQueryParameter || !HttpMethod.GET.name().equals(request.getMethod())) { + return null; + } + + return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME)); + } + + private String resolveAccessTokenFromBody(HttpServletRequest request) { + if (!this.allowFormEncodedBodyParameter + || !MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()) + || HttpMethod.GET.name().equals(request.getMethod())) { + return null; + } + + String queryString = request.getQueryString(); + if (queryString != null && queryString.contains(ACCESS_TOKEN_PARAMETER_NAME)) { + return null; + } + + return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME)); } /** @@ -106,49 +160,4 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { this.bearerTokenHeaderName = bearerTokenHeaderName; } - private String resolveFromAuthorizationHeader(HttpServletRequest request) { - String authorization = request.getHeader(this.bearerTokenHeaderName); - if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { - return null; - } - Matcher matcher = authorizationPattern.matcher(authorization); - if (!matcher.matches()) { - BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); - throw new OAuth2AuthenticationException(error); - } - return matcher.group("token"); - } - - private String resolveFromRequestParameters(HttpServletRequest request) { - if (!isParameterTokenEnabledForRequest(request)) { - return null; - } - String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME); - if (values == null || values.length == 0) { - return null; - } - if (values.length == 1) { - return values[0]; - } - BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } - - private static boolean isGetRequest(HttpServletRequest request) { - return HttpMethod.GET.name().equals(request.getMethod()); - } - - private static boolean isFormEncodedRequest(HttpServletRequest request) { - return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()); - } - - private static boolean hasAccessTokenInQueryString(HttpServletRequest request) { - return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME); - } - - private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) { - return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request) - && !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request))); - } - } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index ec7675acd0..c3c7699f8e 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java index 6c62d7c27f..db8c6292bd 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -237,6 +237,19 @@ public class DefaultBearerTokenResolverTests { assertThat(this.resolver.resolve(request)).isNull(); } + @Test + public void resolveWhenPostAndQueryParameterIsSupportedAndFormParameterIsPresentThenTokenIsNotResolved() { + this.resolver.setAllowUriQueryParameter(true); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("application/x-www-form-urlencoded"); + request.setQueryString("access_token=" + TEST_TOKEN); + request.addParameter("access_token", TEST_TOKEN); + + assertThat(this.resolver.resolve(request)).isNull(); + } + @Test public void resolveWhenFormParameterIsPresentAndNotSupportedThenTokenIsNotResolved() { MockHttpServletRequest request = new MockHttpServletRequest(); @@ -267,7 +280,7 @@ public class DefaultBearerTokenResolverTests { // gh-16038 @Test - void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() { + public void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("POST"); request.setContentType("application/x-www-form-urlencoded"); @@ -277,7 +290,7 @@ public class DefaultBearerTokenResolverTests { // gh-16038 @Test - void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { + public void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("GET"); request.addParameter("access_token", "token1", "token2"); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index 3e47401824..32349f121d 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 9674532f4dbf63fa1257ab11d62f2de01dee12b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Tue, 17 Sep 2024 11:17:32 +0200 Subject: [PATCH 025/504] Add support for access token in body parameter as per rfc 6750 Sec. 2.2 Issue gh-15818 --- ...verBearerTokenAuthenticationConverter.java | 123 +++++++++++++----- ...arerTokenAuthenticationConverterTests.java | 104 +++++++++++++++ 2 files changed, 198 insertions(+), 29 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index c3c7699f8e..67d3105d7d 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -16,14 +16,20 @@ package org.springframework.security.oauth2.server.resource.web.server.authentication; +import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidRequest; + import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; @@ -47,16 +53,20 @@ import org.springframework.web.server.ServerWebExchange; */ public class ServerBearerTokenAuthenticationConverter implements ServerAuthenticationConverter { + public static final String ACCESS_TOKEN_NAME = "access_token"; + public static final String MULTIPLE_BEARER_TOKENS_ERROR_MSG = "Found multiple bearer tokens in the request"; private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+=*)$", Pattern.CASE_INSENSITIVE); private boolean allowUriQueryParameter = false; + private boolean allowFormEncodedBodyParameter = false; + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; @Override public Mono convert(ServerWebExchange exchange) { - return Mono.fromCallable(() -> token(exchange.getRequest())).map((token) -> { + return Mono.defer(() -> token(exchange)).map(token -> { if (token.isEmpty()) { BearerTokenError error = invalidTokenError(); throw new OAuth2AuthenticationException(error); @@ -65,43 +75,53 @@ public class ServerBearerTokenAuthenticationConverter implements ServerAuthentic }); } - private String token(ServerHttpRequest request) { - String authorizationHeaderToken = resolveFromAuthorizationHeader(request.getHeaders()); - String parameterToken = resolveAccessTokenFromRequest(request); + private Mono token(ServerWebExchange exchange) { + final ServerHttpRequest request = exchange.getRequest(); - if (authorizationHeaderToken != null) { - if (parameterToken != null) { - BearerTokenError error = BearerTokenErrors - .invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } - return authorizationHeaderToken; - } - if (parameterToken != null && !StringUtils.hasText(parameterToken)) { - BearerTokenError error = BearerTokenErrors - .invalidRequest("The requested token parameter is an empty string"); - throw new OAuth2AuthenticationException(error); - } - return parameterToken; + return Flux.merge(resolveFromAuthorizationHeader(request.getHeaders()).map(s -> Tuples.of(s, TokenSource.HEADER)), + resolveAccessTokenFromRequest(request).map(s -> Tuples.of(s, TokenSource.QUERY_PARAMETER)), + resolveAccessTokenFromBody(exchange).map(s -> Tuples.of(s, TokenSource.BODY_PARAMETER))) + .collectList() + .mapNotNull(tokenTuples -> { + switch (tokenTuples.size()) { + case 0: + return null; + case 1: + return getTokenIfSupported(tokenTuples.get(0), request); + default: + BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); + throw new OAuth2AuthenticationException(error); + } + }); } - private String resolveAccessTokenFromRequest(ServerHttpRequest request) { - if (!isParameterTokenSupportedForRequest(request)) { - return null; - } - List parameterTokens = request.getQueryParams().get("access_token"); + private static Mono resolveAccessTokenFromRequest(ServerHttpRequest request) { + List parameterTokens = request.getQueryParams().get(ACCESS_TOKEN_NAME); if (CollectionUtils.isEmpty(parameterTokens)) { - return null; + return Mono.empty(); } if (parameterTokens.size() == 1) { - return parameterTokens.get(0); + return Mono.just(parameterTokens.get(0)); } - BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); + BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); throw new OAuth2AuthenticationException(error); } + private String getTokenIfSupported(Tuple2 tokenTuple, ServerHttpRequest request) { + switch (tokenTuple.getT2()) { + case HEADER: + return tokenTuple.getT1(); + case QUERY_PARAMETER: + return isParameterTokenSupportedForRequest(request) ? tokenTuple.getT1() : null; + case BODY_PARAMETER: + return isBodyParameterTokenSupportedForRequest(request) ? tokenTuple.getT1() : null; + default: + throw new IllegalArgumentException(); + } + } + /** * Set if transport of access token using URI query parameter is supported. Defaults * to {@code false}. @@ -127,25 +147,70 @@ public class ServerBearerTokenAuthenticationConverter implements ServerAuthentic this.bearerTokenHeaderName = bearerTokenHeaderName; } - private String resolveFromAuthorizationHeader(HttpHeaders headers) { + /** + * Set if transport of access token using form-encoded body parameter is supported. + * Defaults to {@code false}. + * @param allowFormEncodedBodyParameter if the form-encoded body parameter is + * supported + * @since 6.5 + */ + public void setAllowFormEncodedBodyParameter(boolean allowFormEncodedBodyParameter) { + this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter; + } + + private Mono resolveFromAuthorizationHeader(HttpHeaders headers) { String authorization = headers.getFirst(this.bearerTokenHeaderName); if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { - return null; + return Mono.empty(); } Matcher matcher = authorizationPattern.matcher(authorization); if (!matcher.matches()) { BearerTokenError error = invalidTokenError(); throw new OAuth2AuthenticationException(error); } - return matcher.group("token"); + return Mono.just(matcher.group("token")); } private static BearerTokenError invalidTokenError() { return BearerTokenErrors.invalidToken("Bearer token is malformed"); } + private Mono resolveAccessTokenFromBody(ServerWebExchange exchange) { + if (!allowFormEncodedBodyParameter) { + return Mono.empty(); + } + + final ServerHttpRequest request = exchange.getRequest(); + + if (request.getMethod() == HttpMethod.POST && + MediaType.APPLICATION_FORM_URLENCODED.equalsTypeAndSubtype(request.getHeaders().getContentType())) { + + return exchange.getFormData().mapNotNull(formData -> { + if (formData.isEmpty()) { + return null; + } + final List tokens = formData.get(ACCESS_TOKEN_NAME); + if (tokens == null) { + return null; + } + if (tokens.size() > 1) { + BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); + throw new OAuth2AuthenticationException(error); + } + return formData.getFirst(ACCESS_TOKEN_NAME); + }); + } + return Mono.empty(); + } + + private boolean isBodyParameterTokenSupportedForRequest(ServerHttpRequest request) { + return this.allowFormEncodedBodyParameter && HttpMethod.POST == request.getMethod(); + } + private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) { return this.allowUriQueryParameter && HttpMethod.GET.equals(request.getMethod()); } + private enum TokenSource {HEADER, QUERY_PARAMETER, BODY_PARAMETER} + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index 32349f121d..e7f80968d7 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -32,6 +32,9 @@ import org.springframework.security.oauth2.server.resource.authentication.Bearer import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; +import static org.springframework.mock.http.server.reactive.MockServerHttpRequest.post; /** * @author Rob Winch @@ -219,6 +222,107 @@ public class ServerBearerTokenAuthenticationConverterTests { } + @Test + void resolveWhenBodyParameterIsPresentThenTokenIsResolved() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); + } + + + @Test + void resolveWhenBodyParameterIsPresentButNotAllowedThenTokenIsNotResolved() { + this.converter.setAllowFormEncodedBodyParameter(false); + MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThat(convertToToken(request)).isNull(); + } + + @Test + void resolveWhenBodyParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN + "&access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class) + .isThrownBy(() -> convertToToken(request)) + .satisfies(ex -> { + BearerTokenError error = (BearerTokenError) ex.getError(); + assertThat(error.getDescription()).isEqualTo("Found multiple bearer tokens in the request"); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); + assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1"); + assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); + }); + } + + @Test + void resolveBodyContainsOtherParameterAsWellThenTokenIsResolved() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN + "&other_param=value"); + + assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); + } + + @Test + void resolveWhenNoBodyParameterThenTokenIsNotResolved() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest.BaseBuilder request = post("/").contentType(APPLICATION_FORM_URLENCODED); + + assertThat(convertToToken(request)).isNull(); + } + + @Test + void resolveWhenWrongBodyParameterThenTokenIsNotResolved() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) + .body("other_param=value"); + + assertThat(convertToToken(request)).isNull(); + } + + @Test + void resolveWhenValidHeaderIsPresentTogetherWithBodyParameterThenAuthenticationExceptionIsThrown() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").header(AUTHORIZATION, "Bearer " + TEST_TOKEN) + .contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class) + .isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + void resolveWhenValidQueryParameterIsPresentTogetherWithBodyParameterThenAuthenticationExceptionIsThrown() { + this.converter.setAllowUriQueryParameter(true); + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").queryParam("access_token", TEST_TOKEN) + .contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class) + .isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + void resolveWhenValidQueryParameterIsPresentTogetherWithBodyParameterAndValidHeaderThenAuthenticationExceptionIsThrown() { + this.converter.setAllowUriQueryParameter(true); + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = post("/").header(AUTHORIZATION, "Bearer " + TEST_TOKEN) + .queryParam("access_token", TEST_TOKEN) + .contentType(APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class) + .isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + // gh-16038 @Test void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { From 1fb3fc80f94ef131fcee3830824e2e17ec6be999 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:54:04 -0500 Subject: [PATCH 026/504] Polish gh-15819 Closes gh-15818 --- ...verBearerTokenAuthenticationConverter.java | 170 +++++++----------- ...arerTokenAuthenticationConverterTests.java | 154 ++++++++-------- 2 files changed, 147 insertions(+), 177 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index 67d3105d7d..4575c125cf 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -16,16 +16,12 @@ package org.springframework.security.oauth2.server.resource.web.server.authentication; -import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidRequest; - import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.util.function.Tuple2; -import reactor.util.function.Tuples; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -38,6 +34,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.util.CollectionUtils; +import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; @@ -53,73 +50,89 @@ import org.springframework.web.server.ServerWebExchange; */ public class ServerBearerTokenAuthenticationConverter implements ServerAuthenticationConverter { - public static final String ACCESS_TOKEN_NAME = "access_token"; - public static final String MULTIPLE_BEARER_TOKENS_ERROR_MSG = "Found multiple bearer tokens in the request"; + private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token"; + private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+=*)$", Pattern.CASE_INSENSITIVE); - private boolean allowUriQueryParameter = false; - private boolean allowFormEncodedBodyParameter = false; + private boolean allowUriQueryParameter = false; + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; @Override public Mono convert(ServerWebExchange exchange) { - return Mono.defer(() -> token(exchange)).map(token -> { - if (token.isEmpty()) { - BearerTokenError error = invalidTokenError(); - throw new OAuth2AuthenticationException(error); - } - return new BearerTokenAuthenticationToken(token); + return Mono.defer(() -> { + ServerHttpRequest request = exchange.getRequest(); + // @formatter:off + return Flux.merge(resolveFromAuthorizationHeader(request.getHeaders()), + resolveAccessTokenFromQueryString(request), + resolveAccessTokenFromBody(exchange)) + .collectList() + .flatMap(ServerBearerTokenAuthenticationConverter::resolveToken) + .map(BearerTokenAuthenticationToken::new); + // @formatter:on }); } - private Mono token(ServerWebExchange exchange) { - final ServerHttpRequest request = exchange.getRequest(); - - return Flux.merge(resolveFromAuthorizationHeader(request.getHeaders()).map(s -> Tuples.of(s, TokenSource.HEADER)), - resolveAccessTokenFromRequest(request).map(s -> Tuples.of(s, TokenSource.QUERY_PARAMETER)), - resolveAccessTokenFromBody(exchange).map(s -> Tuples.of(s, TokenSource.BODY_PARAMETER))) - .collectList() - .mapNotNull(tokenTuples -> { - switch (tokenTuples.size()) { - case 0: - return null; - case 1: - return getTokenIfSupported(tokenTuples.get(0), request); - default: - BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); - throw new OAuth2AuthenticationException(error); - } - }); - } - - private static Mono resolveAccessTokenFromRequest(ServerHttpRequest request) { - List parameterTokens = request.getQueryParams().get(ACCESS_TOKEN_NAME); - if (CollectionUtils.isEmpty(parameterTokens)) { + private static Mono resolveToken(List accessTokens) { + if (CollectionUtils.isEmpty(accessTokens)) { return Mono.empty(); } - if (parameterTokens.size() == 1) { - return Mono.just(parameterTokens.get(0)); + + if (accessTokens.size() > 1) { + BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); + return Mono.error(new OAuth2AuthenticationException(error)); } - BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); - throw new OAuth2AuthenticationException(error); + String accessToken = accessTokens.get(0); + if (!StringUtils.hasText(accessToken)) { + BearerTokenError error = BearerTokenErrors + .invalidRequest("The requested token parameter is an empty string"); + return Mono.error(new OAuth2AuthenticationException(error)); + } + return Mono.just(accessToken); } - private String getTokenIfSupported(Tuple2 tokenTuple, ServerHttpRequest request) { - switch (tokenTuple.getT2()) { - case HEADER: - return tokenTuple.getT1(); - case QUERY_PARAMETER: - return isParameterTokenSupportedForRequest(request) ? tokenTuple.getT1() : null; - case BODY_PARAMETER: - return isBodyParameterTokenSupportedForRequest(request) ? tokenTuple.getT1() : null; - default: - throw new IllegalArgumentException(); + private Mono resolveFromAuthorizationHeader(HttpHeaders headers) { + String authorization = headers.getFirst(this.bearerTokenHeaderName); + if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { + return Mono.empty(); } + + Matcher matcher = authorizationPattern.matcher(authorization); + if (!matcher.matches()) { + BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); + throw new OAuth2AuthenticationException(error); + } + + return Mono.just(matcher.group("token")); + } + + private Flux resolveAccessTokenFromQueryString(ServerHttpRequest request) { + if (!this.allowUriQueryParameter || !HttpMethod.GET.equals(request.getMethod())) { + return Flux.empty(); + } + + return resolveTokens(request.getQueryParams()); + } + + private Flux resolveAccessTokenFromBody(ServerWebExchange exchange) { + ServerHttpRequest request = exchange.getRequest(); + if (!this.allowFormEncodedBodyParameter + || !MediaType.APPLICATION_FORM_URLENCODED.equals(request.getHeaders().getContentType()) + || !HttpMethod.POST.equals(request.getMethod())) { + return Flux.empty(); + } + + return exchange.getFormData().flatMapMany(ServerBearerTokenAuthenticationConverter::resolveTokens); + } + + private static Flux resolveTokens(MultiValueMap parameters) { + List accessTokens = parameters.get(ACCESS_TOKEN_PARAMETER_NAME); + return CollectionUtils.isEmpty(accessTokens) ? Flux.empty() : Flux.fromIterable(accessTokens); } /** @@ -158,59 +171,4 @@ public class ServerBearerTokenAuthenticationConverter implements ServerAuthentic this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter; } - private Mono resolveFromAuthorizationHeader(HttpHeaders headers) { - String authorization = headers.getFirst(this.bearerTokenHeaderName); - if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { - return Mono.empty(); - } - Matcher matcher = authorizationPattern.matcher(authorization); - if (!matcher.matches()) { - BearerTokenError error = invalidTokenError(); - throw new OAuth2AuthenticationException(error); - } - return Mono.just(matcher.group("token")); - } - - private static BearerTokenError invalidTokenError() { - return BearerTokenErrors.invalidToken("Bearer token is malformed"); - } - - private Mono resolveAccessTokenFromBody(ServerWebExchange exchange) { - if (!allowFormEncodedBodyParameter) { - return Mono.empty(); - } - - final ServerHttpRequest request = exchange.getRequest(); - - if (request.getMethod() == HttpMethod.POST && - MediaType.APPLICATION_FORM_URLENCODED.equalsTypeAndSubtype(request.getHeaders().getContentType())) { - - return exchange.getFormData().mapNotNull(formData -> { - if (formData.isEmpty()) { - return null; - } - final List tokens = formData.get(ACCESS_TOKEN_NAME); - if (tokens == null) { - return null; - } - if (tokens.size() > 1) { - BearerTokenError error = invalidRequest(MULTIPLE_BEARER_TOKENS_ERROR_MSG); - throw new OAuth2AuthenticationException(error); - } - return formData.getFirst(ACCESS_TOKEN_NAME); - }); - } - return Mono.empty(); - } - - private boolean isBodyParameterTokenSupportedForRequest(ServerHttpRequest request) { - return this.allowFormEncodedBodyParameter && HttpMethod.POST == request.getMethod(); - } - - private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) { - return this.allowUriQueryParameter && HttpMethod.GET.equals(request.getMethod()); - } - - private enum TokenSource {HEADER, QUERY_PARAMETER, BODY_PARAMETER} - } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index e7f80968d7..eeb55c61fb 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; @@ -32,9 +33,6 @@ import org.springframework.security.oauth2.server.resource.authentication.Bearer import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; -import static org.springframework.mock.http.server.reactive.MockServerHttpRequest.post; /** * @author Rob Winch @@ -159,6 +157,7 @@ public class ServerBearerTokenAuthenticationConverterTests { @Test public void resolveWhenValidHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() { + this.converter.setAllowUriQueryParameter(true); // @formatter:off this.converter.setAllowUriQueryParameter(true); MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") @@ -170,6 +169,54 @@ public class ServerBearerTokenAuthenticationConverterTests { // @formatter:on } + @Test + public void resolveWhenValidHeaderIsPresentTogetherWithBodyParameterThenAuthenticationExceptionIsThrown() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + public void resolveWhenValidHeaderIsPresentTogetherWithBodyParameterAndQueryParameterThenAuthenticationExceptionIsThrown() { + this.converter.setAllowUriQueryParameter(true); + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN) + .queryParam("access_token", TEST_TOKEN) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + public void resolveWhenRequestContainsTwoAccessTokenQueryParametersThenAuthenticationExceptionIsThrown() { + this.converter.setAllowUriQueryParameter(true); + MockServerHttpRequest request = MockServerHttpRequest.get("/") + .queryParam("access_token", "token1", "token2") + .build(); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + public void resolveWhenRequestContainsTwoAccessTokenBodyParametersThenAuthenticationExceptionIsThrown() { + this.converter.setAllowFormEncodedBodyParameter(true); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN + "&access_token=" + TEST_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + @Test public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved() { this.converter.setAllowUriQueryParameter(true); @@ -208,7 +255,7 @@ public class ServerBearerTokenAuthenticationConverterTests { } @Test - void resolveWhenQueryParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { + public void resolveWhenQueryParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { this.converter.setAllowUriQueryParameter(true); MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") .queryParam("access_token", TEST_TOKEN, TEST_TOKEN); @@ -223,109 +270,74 @@ public class ServerBearerTokenAuthenticationConverterTests { } @Test - void resolveWhenBodyParameterIsPresentThenTokenIsResolved() { + public void resolveWhenBodyParameterIsPresentThenTokenIsResolved() { this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); } - @Test - void resolveWhenBodyParameterIsPresentButNotAllowedThenTokenIsNotResolved() { + public void resolveWhenBodyParameterIsPresentButNotAllowedThenTokenIsNotResolved() { this.converter.setAllowFormEncodedBodyParameter(false); - MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN); assertThat(convertToToken(request)).isNull(); } @Test - void resolveWhenBodyParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { + public void resolveWhenBodyParameterHasMultipleAccessTokensThenOAuth2AuthenticationException() { this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN + "&access_token=" + TEST_TOKEN); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN + "&access_token=" + TEST_TOKEN); - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> convertToToken(request)) - .satisfies(ex -> { - BearerTokenError error = (BearerTokenError) ex.getError(); - assertThat(error.getDescription()).isEqualTo("Found multiple bearer tokens in the request"); - assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); - assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1"); - assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); - }); + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> convertToToken(request)) + .satisfies((ex) -> { + BearerTokenError error = (BearerTokenError) ex.getError(); + assertThat(error.getDescription()).isEqualTo("Found multiple bearer tokens in the request"); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); + assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1"); + assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); + }); } @Test - void resolveBodyContainsOtherParameterAsWellThenTokenIsResolved() { + public void resolveBodyContainsOtherParameterAsWellThenTokenIsResolved() { this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN + "&other_param=value"); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("access_token=" + TEST_TOKEN + "&other_param=value"); assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); } @Test - void resolveWhenNoBodyParameterThenTokenIsNotResolved() { + public void resolveWhenNoBodyParameterThenTokenIsNotResolved() { this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest.BaseBuilder request = post("/").contentType(APPLICATION_FORM_URLENCODED); + MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED); assertThat(convertToToken(request)).isNull(); } @Test - void resolveWhenWrongBodyParameterThenTokenIsNotResolved() { + public void resolveWhenWrongBodyParameterThenTokenIsNotResolved() { this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").contentType(APPLICATION_FORM_URLENCODED) - .body("other_param=value"); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("other_param=value"); assertThat(convertToToken(request)).isNull(); } - @Test - void resolveWhenValidHeaderIsPresentTogetherWithBodyParameterThenAuthenticationExceptionIsThrown() { - this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").header(AUTHORIZATION, "Bearer " + TEST_TOKEN) - .contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN); - - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> convertToToken(request)) - .withMessageContaining("Found multiple bearer tokens in the request"); - } - - @Test - void resolveWhenValidQueryParameterIsPresentTogetherWithBodyParameterThenAuthenticationExceptionIsThrown() { - this.converter.setAllowUriQueryParameter(true); - this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").queryParam("access_token", TEST_TOKEN) - .contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN); - - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> convertToToken(request)) - .withMessageContaining("Found multiple bearer tokens in the request"); - } - - @Test - void resolveWhenValidQueryParameterIsPresentTogetherWithBodyParameterAndValidHeaderThenAuthenticationExceptionIsThrown() { - this.converter.setAllowUriQueryParameter(true); - this.converter.setAllowFormEncodedBodyParameter(true); - MockServerHttpRequest request = post("/").header(AUTHORIZATION, "Bearer " + TEST_TOKEN) - .queryParam("access_token", TEST_TOKEN) - .contentType(APPLICATION_FORM_URLENCODED) - .body("access_token=" + TEST_TOKEN); - - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> convertToToken(request)) - .withMessageContaining("Found multiple bearer tokens in the request"); - } - // gh-16038 @Test - void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { + public void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() { MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest.get("/") .queryParam("access_token", TEST_TOKEN, TEST_TOKEN); assertThat(convertToToken(request)).isNull(); From f93a7a2f85c588a02b8d79845da2b90c56664cb7 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:09:19 -0600 Subject: [PATCH 027/504] Deprecate HandlerMappingIntrospectorRequestTransformer Closes gh-16536 --- .../annotation/web/builders/WebSecurity.java | 70 ++++--- .../WebMvcSecurityConfiguration.java | 37 ++-- .../WebSecurityConfiguration.java | 192 ++++++++++++++++++ .../WebSecurityConfigurationRuntimeHints.java | 40 ++++ .../config/http/HttpConfigurationBuilder.java | 10 +- .../WebSecurityConfigurationTests.java | 75 +++++++ docs/modules/ROOT/pages/migration-7/web.adoc | 48 +++++ .../security/web/FilterChainProxy.java | 41 ++-- ...MappingIntrospectorRequestTransformer.java | 2 + .../access/PathPatternRequestTransformer.java | 70 +++++++ ...gatingWebInvocationPrivilegeEvaluator.java | 37 +--- ...rWebInvocationPrivilegeEvaluatorTests.java | 17 ++ ...gWebInvocationPrivilegeEvaluatorTests.java | 17 -- 13 files changed, 540 insertions(+), 116 deletions(-) create mode 100644 config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java create mode 100644 web/src/main/java/org/springframework/security/web/access/PathPatternRequestTransformer.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java index 479a6ae60c..329859a1f5 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java @@ -35,7 +35,9 @@ import org.springframework.core.ResolvableType; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder; import org.springframework.security.config.annotation.SecurityBuilder; @@ -58,6 +60,8 @@ import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; +import org.springframework.security.web.access.intercept.RequestAuthorizationContext; +import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager; import org.springframework.security.web.debug.DebugFilter; import org.springframework.security.web.firewall.CompositeRequestRejectedHandler; import org.springframework.security.web.firewall.HttpFirewall; @@ -65,6 +69,7 @@ import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandle import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler; import org.springframework.security.web.firewall.RequestRejectedHandler; import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcherEntry; import org.springframework.util.Assert; @@ -230,8 +235,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder securityFilterChains = new ArrayList<>(chainSize); - List>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>(); + RequestMatcherDelegatingAuthorizationManager.Builder builder = RequestMatcherDelegatingAuthorizationManager + .builder(); + boolean mappings = false; for (RequestMatcher ignoredRequest : this.ignoredRequests) { WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest + ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead."); SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest); securityFilterChains.add(securityFilterChain); - requestMatcherPrivilegeEvaluatorsEntries - .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); + builder.add(ignoredRequest, SingleResultAuthorizationManager.permitAll()); + mappings = true; } for (SecurityBuilder securityFilterChainBuilder : this.securityFilterChainBuilders) { SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build(); securityFilterChains.add(securityFilterChain); - requestMatcherPrivilegeEvaluatorsEntries - .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); + mappings = addAuthorizationManager(securityFilterChain, builder) || mappings; } if (this.privilegeEvaluator == null) { + AuthorizationManager authorizationManager = mappings ? builder.build() + : SingleResultAuthorizationManager.permitAll(); + AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator( + authorizationManager); + privilegeEvaluator.setServletContext(this.servletContext); + if (this.privilegeEvaluatorRequestTransformer != null) { + privilegeEvaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer); + } this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator( - requestMatcherPrivilegeEvaluatorsEntries); + List.of(new RequestMatcherEntry<>(AnyRequestMatcher.INSTANCE, List.of(privilegeEvaluator)))); } FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); if (this.httpFirewall != null) { @@ -350,30 +364,32 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder> getRequestMatcherPrivilegeEvaluatorsEntry( - SecurityFilterChain securityFilterChain) { - List privilegeEvaluators = new ArrayList<>(); + private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain, + RequestMatcherDelegatingAuthorizationManager.Builder builder) { + boolean mappings = false; for (Filter filter : securityFilterChain.getFilters()) { - if (filter instanceof FilterSecurityInterceptor) { - DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator( - (FilterSecurityInterceptor) filter); - defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext); - privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator); + if (filter instanceof FilterSecurityInterceptor securityInterceptor) { + DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator( + securityInterceptor); + privilegeEvaluator.setServletContext(this.servletContext); + AuthorizationManager authorizationManager = (authentication, context) -> { + HttpServletRequest request = context.getRequest(); + boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(), + request.getMethod(), authentication.get()); + return new AuthorizationDecision(result); + }; + builder.add(securityFilterChain::matches, authorizationManager); + mappings = true; continue; } - if (filter instanceof AuthorizationFilter) { - AuthorizationManager authorizationManager = ((AuthorizationFilter) filter) - .getAuthorizationManager(); - AuthorizationManagerWebInvocationPrivilegeEvaluator evaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator( - authorizationManager); - evaluator.setServletContext(this.servletContext); - if (this.privilegeEvaluatorRequestTransformer != null) { - evaluator.setRequestTransformer(this.privilegeEvaluatorRequestTransformer); - } - privilegeEvaluators.add(evaluator); + if (filter instanceof AuthorizationFilter authorization) { + AuthorizationManager authorizationManager = authorization.getAuthorizationManager(); + builder.add(securityFilterChain::matches, + (authentication, context) -> authorizationManager.check(authentication, context.getRequest())); + mappings = true; } } - return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators); + return mappings; } @Override diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java index 3f03140a46..85dd907ff8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java @@ -78,6 +78,8 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; + private static final String PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME = "pathPatternRequestTransformer"; + private BeanResolver beanResolver; private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder @@ -119,18 +121,8 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex } } - /** - * Used to ensure Spring MVC request matching is cached. - * - * Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named - * HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the - * AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name - * and then adds a {@link CompositeFilter} that contains - * {@link HandlerMappingIntrospector#createCacheFilter()} and the original - * FilterChainProxy under the original Bean name. - * @return - */ @Bean + @Deprecated static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() { return new BeanDefinitionRegistryPostProcessor() { @Override @@ -144,12 +136,15 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex } String hmiRequestTransformerBeanName = HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + "RequestTransformer"; - if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { - BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder - .rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class) - .addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME) - .getBeanDefinition(); - registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer); + if (!registry.containsBeanDefinition(PATH_PATTERN_REQUEST_TRANSFORMER_BEAN_NAME) + && !registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { + if (!registry.containsBeanDefinition(hmiRequestTransformerBeanName)) { + BeanDefinition hmiRequestTransformer = BeanDefinitionBuilder + .rootBeanDefinition(HandlerMappingIntrospectorRequestTransformer.class) + .addConstructorArgReference(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME) + .getBeanDefinition(); + registry.registerBeanDefinition(hmiRequestTransformerBeanName, hmiRequestTransformer); + } } BeanDefinition filterChainProxy = registry @@ -178,7 +173,11 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex /** * {@link FactoryBean} to defer creation of * {@link HandlerMappingIntrospector#createCacheFilter()} + * + * @deprecated see {@link WebSecurityConfiguration} for + * {@link org.springframework.web.util.pattern.PathPattern} replacement */ + @Deprecated static class HandlerMappingIntrospectorCacheFilterFactoryBean implements ApplicationContextAware, FactoryBean { @@ -207,7 +206,11 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex * Extends {@link FilterChainProxy} to provide as much passivity as possible but * delegates to {@link CompositeFilter} for * {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}. + * + * @deprecated see {@link WebSecurityConfiguration} for + * {@link org.springframework.web.util.pattern.PathPattern} replacement */ + @Deprecated static class CompositeFilterChainProxy extends FilterChainProxy { /** diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java index f58e9e55fc..d1f6ae8699 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java @@ -16,16 +16,29 @@ package org.springframework.security.config.annotation.web.configuration; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.ManagedList; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; @@ -45,11 +58,18 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor; import org.springframework.security.context.DelegatingApplicationListener; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; +import org.springframework.security.web.debug.DebugFilter; +import org.springframework.security.web.firewall.HttpFirewall; +import org.springframework.security.web.firewall.RequestRejectedHandler; +import org.springframework.web.filter.CompositeFilter; +import org.springframework.web.filter.ServletRequestPathFilter; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; /** * Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web @@ -186,6 +206,56 @@ public class WebSecurityConfiguration implements ImportAware { } } + /** + * Used to ensure Spring MVC request matching is cached. + * + * Creates a {@link BeanDefinitionRegistryPostProcessor} that detects if a bean named + * HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME is defined. If so, it moves the + * AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME to another bean name + * and then adds a {@link CompositeFilter} that contains + * {@link HandlerMappingIntrospector#createCacheFilter()} and the original + * FilterChainProxy under the original Bean name. + * @return + */ + @Bean + static BeanDefinitionRegistryPostProcessor springSecurityPathPatternParserBeanDefinitionRegistryPostProcessor() { + return new BeanDefinitionRegistryPostProcessor() { + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + } + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + BeanDefinition filterChainProxy = registry + .getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); + + if (filterChainProxy.getResolvableType().isAssignableFrom(CompositeFilterChainProxy.class)) { + return; + } + + BeanDefinitionBuilder pppCacheFilterBldr = BeanDefinitionBuilder + .rootBeanDefinition(ServletRequestPathFilter.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + + ManagedList filters = new ManagedList<>(); + filters.add(pppCacheFilterBldr.getBeanDefinition()); + filters.add(filterChainProxy); + BeanDefinitionBuilder compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder + .rootBeanDefinition(CompositeFilterChainProxy.class) + .addConstructorArgValue(filters); + + if (filterChainProxy.getResolvableType().isInstance(DebugFilter.class)) { + compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder.rootBeanDefinition(DebugFilter.class) + .addConstructorArgValue(compositeSpringSecurityFilterChainBldr.getBeanDefinition()); + } + + registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); + registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, + compositeSpringSecurityFilterChainBldr.getBeanDefinition()); + } + }; + } + /** * A custom version of the Spring provided AnnotationAwareOrderComparator that uses * {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class @@ -219,4 +289,126 @@ public class WebSecurityConfiguration implements ImportAware { } + /** + * Extends {@link FilterChainProxy} to provide as much passivity as possible but + * delegates to {@link CompositeFilter} for + * {@link #doFilter(ServletRequest, ServletResponse, FilterChain)}. + */ + static class CompositeFilterChainProxy extends FilterChainProxy { + + /** + * Used for {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} + */ + private final Filter doFilterDelegate; + + private final FilterChainProxy springSecurityFilterChain; + + /** + * Creates a new instance + * @param filters the Filters to delegate to. One of which must be + * FilterChainProxy. + */ + CompositeFilterChainProxy(List filters) { + this.doFilterDelegate = createDoFilterDelegate(filters); + this.springSecurityFilterChain = findFilterChainProxy(filters); + } + + CompositeFilterChainProxy(Filter delegate, FilterChainProxy filterChain) { + this.doFilterDelegate = delegate; + this.springSecurityFilterChain = filterChain; + } + + @Override + public void afterPropertiesSet() { + this.springSecurityFilterChain.afterPropertiesSet(); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + this.doFilterDelegate.doFilter(request, response, chain); + } + + @Override + public List getFilters(String url) { + return this.springSecurityFilterChain.getFilters(url); + } + + @Override + public List getFilterChains() { + return this.springSecurityFilterChain.getFilterChains(); + } + + @Override + public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + this.springSecurityFilterChain.setSecurityContextHolderStrategy(securityContextHolderStrategy); + } + + @Override + public void setFilterChainValidator(FilterChainValidator filterChainValidator) { + this.springSecurityFilterChain.setFilterChainValidator(filterChainValidator); + } + + @Override + public void setFilterChainDecorator(FilterChainDecorator filterChainDecorator) { + this.springSecurityFilterChain.setFilterChainDecorator(filterChainDecorator); + } + + @Override + public void setFirewall(HttpFirewall firewall) { + this.springSecurityFilterChain.setFirewall(firewall); + } + + @Override + public void setRequestRejectedHandler(RequestRejectedHandler requestRejectedHandler) { + this.springSecurityFilterChain.setRequestRejectedHandler(requestRejectedHandler); + } + + /** + * Used through reflection by Spring Security's Test support to lookup the + * FilterChainProxy Filters for a specific HttpServletRequest. + * @param request + * @return + */ + private List getFilters(HttpServletRequest request) { + List filterChains = this.springSecurityFilterChain.getFilterChains(); + for (SecurityFilterChain chain : filterChains) { + if (chain.matches(request)) { + return chain.getFilters(); + } + } + return null; + } + + /** + * Creates the Filter to delegate to for doFilter + * @param filters the Filters to delegate to. + * @return the Filter for doFilter + */ + private static Filter createDoFilterDelegate(List filters) { + CompositeFilter delegate = new CompositeFilter(); + delegate.setFilters(filters); + return delegate; + } + + /** + * Find the FilterChainProxy in a List of Filter + * @param filters + * @return non-null FilterChainProxy + * @throws IllegalStateException if the FilterChainProxy cannot be found + */ + private static FilterChainProxy findFilterChainProxy(List filters) { + for (Filter filter : filters) { + if (filter instanceof FilterChainProxy fcp) { + return fcp; + } + if (filter instanceof DebugFilter debugFilter) { + return new CompositeFilterChainProxy(debugFilter, debugFilter.getFilterChainProxy()); + } + } + throw new IllegalStateException("Couldn't find FilterChainProxy in " + filters); + } + + } + } diff --git a/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java new file mode 100644 index 0000000000..bf1b184179 --- /dev/null +++ b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.config.aot.hint; + +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; + +/** + * Runtime hints for + * {@link org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration} + * + * @author Marcus da Coregio + */ +class WebSecurityConfigurationRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection() + .registerType(TypeReference + .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy"), + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + +} diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java index fd18eb3362..1b22c044f6 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java @@ -51,6 +51,7 @@ import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.HandlerMappingIntrospectorRequestTransformer; +import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl; import org.springframework.security.web.access.channel.ChannelProcessingFilter; import org.springframework.security.web.access.channel.InsecureChannelProcessor; @@ -974,10 +975,17 @@ class HttpConfigurationBuilder { @Override public AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer getObject() throws Exception { + AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer requestTransformer = this.applicationContext + .getBeanProvider( + AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer.class) + .getIfUnique(); + if (requestTransformer != null) { + return requestTransformer; + } HandlerMappingIntrospector hmi = this.applicationContext.getBeanProvider(HandlerMappingIntrospector.class) .getIfAvailable(); return (hmi != null) ? new HandlerMappingIntrospectorRequestTransformer(hmi) - : AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer.IDENTITY; + : new PathPatternRequestTransformer(); } @Override diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java index e546ffb6a1..f96d67809e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java @@ -57,9 +57,12 @@ import org.springframework.security.core.Authentication; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator; +import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.ClassUtils; @@ -69,8 +72,12 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -320,6 +327,27 @@ public class WebSecurityConfigurationTests { assertThat(privilegeEvaluator.isAllowed("/ignoring1/child", null)).isTrue(); } + @Test + public void loadConfigWhenUsePathPatternThenEvaluates() { + this.spring.register(UsePathPatternConfig.class).autowire(); + WebInvocationPrivilegeEvaluator privilegeEvaluator = this.spring.getContext() + .getBean(WebInvocationPrivilegeEvaluator.class); + assertUserPermissions(privilegeEvaluator); + assertAdminPermissions(privilegeEvaluator); + assertAnotherUserPermission(privilegeEvaluator); + // null authentication + assertThat(privilegeEvaluator.isAllowed("/user", null)).isFalse(); + assertThat(privilegeEvaluator.isAllowed("/admin", null)).isFalse(); + assertThat(privilegeEvaluator.isAllowed("/another", null)).isTrue(); + assertThat(privilegeEvaluator.isAllowed("/ignoring1", null)).isTrue(); + assertThat(privilegeEvaluator.isAllowed("/ignoring1/child", null)).isTrue(); + AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer requestTransformer = this.spring + .getContext() + .getBean(AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer.class); + verify(requestTransformer, atLeastOnce()).transform(any()); + + } + @Test public void loadConfigWhenTwoSecurityFilterChainsPresentAndSecondWithAnyRequestThenException() { assertThatExceptionOfType(BeanCreationException.class) @@ -862,6 +890,53 @@ public class WebSecurityConfigurationTests { } + @Configuration + @EnableWebSecurity + @EnableWebMvc + @Import(AuthenticationTestConfiguration.class) + static class UsePathPatternConfig { + + @Bean + AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer pathPatternRequestTransformer() { + return spy(new PathPatternRequestTransformer()); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().requestMatchers("/ignoring1/**"); + } + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception { + // @formatter:off + http + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user"))) + .authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("USER")); + // @formatter:on + return http.build(); + } + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE + 1) + public SecurityFilterChain admin(HttpSecurity http) throws Exception { + // @formatter:off + http + .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin"))) + .authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ADMIN")); + // @formatter:on + return http.build(); + } + + @Bean + @Order(Ordered.LOWEST_PRECEDENCE) + public SecurityFilterChain permitAll(HttpSecurity http) throws Exception { + http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); + return http.build(); + } + + } + @Configuration @EnableWebSecurity @EnableWebMvc diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc index aa898da4fd..330d87ddc2 100644 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ b/docs/modules/ROOT/pages/migration-7/web.adoc @@ -339,6 +339,54 @@ casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().m ---- ====== +=== 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. diff --git a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java index f9ad696436..c71ea74930 100644 --- a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java +++ b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java @@ -46,7 +46,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.filter.GenericFilterBean; -import org.springframework.web.filter.ServletRequestPathFilter; /** * Delegates {@code Filter} requests to a list of Spring-managed filter beans. As of @@ -163,8 +162,6 @@ public class FilterChainProxy extends GenericFilterBean { private FilterChainDecorator filterChainDecorator = new VirtualFilterChainDecorator(); - private Filter springWebFilter = new ServletRequestPathFilter(); - public FilterChainProxy() { } @@ -213,29 +210,27 @@ public class FilterChainProxy extends GenericFilterBean { throws IOException, ServletException { FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request); HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response); - this.springWebFilter.doFilter(firewallRequest, firewallResponse, (r, s) -> { - List filters = getFilters(firewallRequest); - if (filters == null || filters.isEmpty()) { - if (logger.isTraceEnabled()) { - logger.trace(LogMessage.of(() -> "No security for " + requestLine(firewallRequest))); - } - firewallRequest.reset(); - this.filterChainDecorator.decorate(chain).doFilter(firewallRequest, firewallResponse); - return; + List filters = getFilters(firewallRequest); + if (filters == null || filters.isEmpty()) { + if (logger.isTraceEnabled()) { + logger.trace(LogMessage.of(() -> "No security for " + requestLine(firewallRequest))); } + firewallRequest.reset(); + this.filterChainDecorator.decorate(chain).doFilter(firewallRequest, firewallResponse); + return; + } + if (logger.isDebugEnabled()) { + logger.debug(LogMessage.of(() -> "Securing " + requestLine(firewallRequest))); + } + FilterChain reset = (req, res) -> { if (logger.isDebugEnabled()) { - logger.debug(LogMessage.of(() -> "Securing " + requestLine(firewallRequest))); + logger.debug(LogMessage.of(() -> "Secured " + requestLine(firewallRequest))); } - FilterChain reset = (req, res) -> { - if (logger.isDebugEnabled()) { - logger.debug(LogMessage.of(() -> "Secured " + requestLine(firewallRequest))); - } - // Deactivate path stripping as we exit the security filter chain - firewallRequest.reset(); - chain.doFilter(req, res); - }; - this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse); - }); + // Deactivate path stripping as we exit the security filter chain + firewallRequest.reset(); + chain.doFilter(req, res); + }; + this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse); } /** diff --git a/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java b/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java index 42cf51c3c3..f78ad46a50 100644 --- a/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java +++ b/web/src/main/java/org/springframework/security/web/access/HandlerMappingIntrospectorRequestTransformer.java @@ -35,7 +35,9 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; * default throw {@link UnsupportedOperationException}. * * @author Rob Winch + * @deprecated please use {@link PathPatternRequestTransformer} instead */ +@Deprecated(forRemoval = true) public class HandlerMappingIntrospectorRequestTransformer implements AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer { diff --git a/web/src/main/java/org/springframework/security/web/access/PathPatternRequestTransformer.java b/web/src/main/java/org/springframework/security/web/access/PathPatternRequestTransformer.java new file mode 100644 index 0000000000..c77072e3ac --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/access/PathPatternRequestTransformer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.access; + +import java.util.HashMap; +import java.util.Map; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; + +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; +import org.springframework.web.util.ServletRequestPathUtils; + +/** + * Prepares the privilege evaluator's request for {@link PathPatternRequestMatcher} + * authorization rules. + * + * @author Josh Cummings + * @since 6.5 + */ +public final class PathPatternRequestTransformer + implements AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer { + + @Override + public HttpServletRequest transform(HttpServletRequest request) { + HttpServletRequest wrapped = new AttributesSupportingHttpServletRequest(request); + ServletRequestPathUtils.parseAndCache(wrapped); + return wrapped; + } + + private static final class AttributesSupportingHttpServletRequest extends HttpServletRequestWrapper { + + private final Map attributes = new HashMap<>(); + + AttributesSupportingHttpServletRequest(HttpServletRequest request) { + super(request); + } + + @Override + public Object getAttribute(String name) { + return this.attributes.get(name); + } + + @Override + public void setAttribute(String name, Object value) { + this.attributes.put(name, value); + } + + @Override + public void removeAttribute(String name) { + this.attributes.remove(name); + } + + } + +} diff --git a/web/src/main/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java b/web/src/main/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java index f410bf19ef..e50153ce5d 100644 --- a/web/src/main/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java +++ b/web/src/main/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java @@ -17,20 +17,17 @@ package org.springframework.security.web.access; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; +import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.util.matcher.RequestMatcherEntry; import org.springframework.util.Assert; import org.springframework.web.context.ServletContextAware; -import org.springframework.web.util.ServletRequestPathUtils; /** * A {@link WebInvocationPrivilegeEvaluator} which delegates to a list of @@ -39,7 +36,11 @@ import org.springframework.web.util.ServletRequestPathUtils; * * @author Marcus Da Coregio * @since 5.5.5 + * @deprecated please use {@link AuthorizationManagerWebInvocationPrivilegeEvaluator} and + * adapt any delegate {@link WebInvocationPrivilegeEvaluator}s into + * {@link AuthorizationManager}s */ +@Deprecated public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator implements WebInvocationPrivilegeEvaluator, ServletContextAware { @@ -120,8 +121,7 @@ public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator private List getDelegate(String contextPath, String uri, String method) { FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext); - HttpServletRequest request = new AttributesSupportingHttpServletRequest(filterInvocation.getHttpRequest()); - ServletRequestPathUtils.parseAndCache(request); + HttpServletRequest request = filterInvocation.getHttpRequest(); for (RequestMatcherEntry> delegate : this.delegates) { if (delegate.getRequestMatcher().matches(request)) { return delegate.getEntry(); @@ -135,29 +135,4 @@ public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator this.servletContext = servletContext; } - private static final class AttributesSupportingHttpServletRequest extends HttpServletRequestWrapper { - - private final Map attributes = new HashMap<>(); - - AttributesSupportingHttpServletRequest(HttpServletRequest request) { - super(request); - } - - @Override - public Object getAttribute(String name) { - return this.attributes.get(name); - } - - @Override - public void setAttribute(String name, Object value) { - this.attributes.put(name, value); - } - - @Override - public void removeAttribute(String name) { - this.attributes.remove(name); - } - - } - } diff --git a/web/src/test/java/org/springframework/security/web/access/AuthorizationManagerWebInvocationPrivilegeEvaluatorTests.java b/web/src/test/java/org/springframework/security/web/access/AuthorizationManagerWebInvocationPrivilegeEvaluatorTests.java index afb5ad9e97..0fd298ec96 100644 --- a/web/src/test/java/org/springframework/security/web/access/AuthorizationManagerWebInvocationPrivilegeEvaluatorTests.java +++ b/web/src/test/java/org/springframework/security/web/access/AuthorizationManagerWebInvocationPrivilegeEvaluatorTests.java @@ -31,6 +31,8 @@ import org.springframework.security.authentication.TestAuthentication; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer; +import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager; +import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -111,4 +113,19 @@ class AuthorizationManagerWebInvocationPrivilegeEvaluatorTests { verify(this.authorizationManager).check(any(), eq(request)); } + // gh-16771 + @Test + void isAllowedWhenInvokesDelegateThenCachesRequestPath() { + RequestMatcherDelegatingAuthorizationManager authorizationManager = RequestMatcherDelegatingAuthorizationManager + .builder() + .add(PathPatternRequestMatcher.withDefaults().matcher("/test/**"), + (authentication, context) -> this.authorizationManager.check(authentication, context.getRequest())) + .build(); + AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator = new AuthorizationManagerWebInvocationPrivilegeEvaluator( + authorizationManager); + privilegeEvaluator.setRequestTransformer(new PathPatternRequestTransformer()); + privilegeEvaluator.isAllowed("/test", TestAuthentication.authenticatedUser()); + verify(this.authorizationManager).check(any(), any()); + } + } diff --git a/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java b/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java index 8847cfa93e..ca39fef4be 100644 --- a/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java +++ b/web/src/test/java/org/springframework/security/web/access/RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests.java @@ -22,16 +22,12 @@ import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.springframework.mock.web.MockServletContext; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcherEntry; -import org.springframework.web.util.ServletRequestPathUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -178,19 +174,6 @@ class RequestMatcherDelegatingWebInvocationPrivilegeEvaluatorTests { .withMessageContaining("requestMatcher cannot be null"); } - // gh-16771 - @Test - void isAllowedWhenInvokesDelegateThenCachesRequestPath() { - PathPatternRequestMatcher path = PathPatternRequestMatcher.withDefaults().matcher("/path/**"); - PathPatternRequestMatcher any = PathPatternRequestMatcher.withDefaults().matcher("/**"); - WebInvocationPrivilegeEvaluator delegating = evaluator(deny(path), deny(any)); - try (MockedStatic utils = Mockito.mockStatic(ServletRequestPathUtils.class, - Mockito.CALLS_REAL_METHODS)) { - delegating.isAllowed("/uri", null); - utils.verify(() -> ServletRequestPathUtils.parseAndCache(any()), times(1)); - } - } - @SuppressWarnings({ "rawtypes", "unchecked" }) private RequestMatcherDelegatingWebInvocationPrivilegeEvaluator evaluator(RequestMatcherEntry... entries) { return new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(List.of(entries)); From 8d7f6acab6e2f032be8edf3fd17a5c6b807079a8 Mon Sep 17 00:00:00 2001 From: James Howe <675056+OrangeDog@users.noreply.github.com> Date: Wed, 2 Apr 2025 16:38:13 +0100 Subject: [PATCH 028/504] Typo in Base64StringKeyGenerator exception message Signed-off-by: James Howe <675056+OrangeDog@users.noreply.github.com> --- .../security/crypto/keygen/Base64StringKeyGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java b/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java index 347328bba0..9b28d68a72 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java +++ b/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java @@ -68,7 +68,7 @@ public class Base64StringKeyGenerator implements StringKeyGenerator { throw new IllegalArgumentException("encode cannot be null"); } if (keyLength < DEFAULT_KEY_LENGTH) { - throw new IllegalArgumentException("keyLength must be greater than or equal to" + DEFAULT_KEY_LENGTH); + throw new IllegalArgumentException("keyLength must be greater than or equal to " + DEFAULT_KEY_LENGTH); } this.encoder = encoder; this.keyGenerator = KeyGenerators.secureRandom(keyLength); From d899bc5240ff763eb6818a2978bcabd84f917fd0 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Tue, 8 Apr 2025 19:29:57 +0700 Subject: [PATCH 029/504] Polish javadoc Signed-off-by: Tran Ngoc Nhan --- .../resource/introspection/OpaqueTokenIntrospector.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java index 056a7766b2..0679c9cfbf 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package org.springframework.security.oauth2.server.resource.introspection; -import java.util.Map; - import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; /** @@ -40,7 +38,7 @@ public interface OpaqueTokenIntrospector { /** * Introspect and verify the given token, returning its attributes. * - * Returning a {@link Map} is indicative that the token is valid. + * Returning a {@link OAuth2AuthenticatedPrincipal} is indicative that the token is valid. * @param token the token to introspect * @return the token's attributes */ From d864e51ff634ebcadb62fdff81e9bab25d25f10a Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 9 Apr 2025 01:12:43 +0700 Subject: [PATCH 030/504] Format OpaqueTokenIntrospector Signed-off-by: Tran Ngoc Nhan --- .../server/resource/introspection/OpaqueTokenIntrospector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java index 0679c9cfbf..a670554b69 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/OpaqueTokenIntrospector.java @@ -38,7 +38,8 @@ public interface OpaqueTokenIntrospector { /** * Introspect and verify the given token, returning its attributes. * - * Returning a {@link OAuth2AuthenticatedPrincipal} is indicative that the token is valid. + * Returning a {@link OAuth2AuthenticatedPrincipal} is indicative that the token is + * valid. * @param token the token to introspect * @return the token's attributes */ From bfb4878e298d5f6e4b1dfca7e9ec2fe16359fdae Mon Sep 17 00:00:00 2001 From: Michael Samborski Date: Tue, 1 Apr 2025 10:41:22 -0400 Subject: [PATCH 031/504] Update kotlin.adoc to add required spread operator(*) Signed-off-by: Michael Samborski --- docs/modules/ROOT/pages/servlet/configuration/kotlin.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/configuration/kotlin.adoc b/docs/modules/ROOT/pages/servlet/configuration/kotlin.adoc index 91d62ba0e1..6e0a3befcb 100644 --- a/docs/modules/ROOT/pages/servlet/configuration/kotlin.adoc +++ b/docs/modules/ROOT/pages/servlet/configuration/kotlin.adoc @@ -288,7 +288,7 @@ class BankingSecurityConfig { open fun approvalsSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { val approvalsPaths = arrayOf("/accounts/approvals/**", "/loans/approvals/**", "/credit-cards/approvals/**") http { - securityMatcher(approvalsPaths) + securityMatcher(*approvalsPaths) authorizeHttpRequests { authorize(anyRequest, hasRole("ADMIN")) } @@ -303,7 +303,7 @@ class BankingSecurityConfig { val bankingPaths = arrayOf("/accounts/**", "/loans/**", "/credit-cards/**", "/balances/**") val viewBalancePaths = arrayOf("/balances/**") http { - securityMatcher(bankingPaths) + securityMatcher(*bankingPaths) authorizeHttpRequests { authorize(viewBalancePaths, hasRole("VIEW_BALANCE")) authorize(anyRequest, hasRole("USER")) From 9ca02082dc999b7ec425f29ca22eab3be06059f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 03:35:07 +0000 Subject: [PATCH 032/504] Bump org.jetbrains.kotlinx:kotlinx-coroutines-bom from 1.10.1 to 1.10.2 Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-bom](https://github.com/Kotlin/kotlinx.coroutines) from 1.10.1 to 1.10.2. - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.10.1...1.10.2) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-bom dependency-version: 1.10.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 38b7ee6a19..9a9ab595b6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ org-aspectj = "1.9.22.1" org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" org-jetbrains-kotlin = "1.9.25" -org-jetbrains-kotlinx = "1.10.1" +org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" From 197ee38aa0b7bb92d0e0bbd7622f991214d6192a Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:08:57 -0500 Subject: [PATCH 033/504] Mark deprecated response clients for removal Issue gh-16913 --- .../endpoint/DefaultAuthorizationCodeTokenResponseClient.java | 4 ++-- .../endpoint/DefaultClientCredentialsTokenResponseClient.java | 4 ++-- .../client/endpoint/DefaultJwtBearerTokenResponseClient.java | 4 ++-- .../endpoint/DefaultRefreshTokenTokenResponseClient.java | 4 ++-- .../endpoint/DefaultTokenExchangeTokenResponseClient.java | 4 ++-- .../client/endpoint/JwtBearerGrantRequestEntityConverter.java | 4 ++-- .../OAuth2AuthorizationCodeGrantRequestEntityConverter.java | 4 ++-- .../OAuth2ClientCredentialsGrantRequestEntityConverter.java | 4 ++-- .../OAuth2RefreshTokenGrantRequestEntityConverter.java | 4 ++-- .../endpoint/TokenExchangeGrantRequestEntityConverter.java | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java index 7467487528..9e76af76b9 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ import org.springframework.web.client.RestTemplate; * (Authorization Code Grant) * @deprecated Use {@link RestClientAuthorizationCodeTokenResponseClient} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public final class DefaultAuthorizationCodeTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java index 99a8bbb0c8..a5338dca18 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ import org.springframework.web.client.RestTemplate; * (Client Credentials Grant) * @deprecated Use {@link RestClientClientCredentialsTokenResponseClient} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public final class DefaultClientCredentialsTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClient.java index 48a4523c04..f4e925a57d 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ import org.springframework.web.client.RestTemplate; * 4.1 Using Assertions as Authorization Grants * @deprecated Use {@link RestClientJwtBearerTokenResponseClient} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public final class DefaultJwtBearerTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java index 35e2e37071..924df457fa 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ import org.springframework.web.client.RestTemplate; * Refreshing an Access Token * @deprecated Use {@link RestClientRefreshTokenTokenResponseClient} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public final class DefaultRefreshTokenTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClient.java index 3ba3d889f3..4d42d37ca1 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ import org.springframework.web.client.RestTemplate; * 2.2 Response * @deprecated Use {@link RestClientRefreshTokenTokenResponseClient} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public final class DefaultTokenExchangeTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverter.java index cb187e1655..6486179b92 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ import org.springframework.util.StringUtils; * 2.1 Using JWTs as Authorization Grants * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class JwtBearerGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverter.java index 52bab99b13..15e021dc14 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ import org.springframework.util.MultiValueMap; * @see RequestEntity * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class OAuth2AuthorizationCodeGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverter.java index 4e24648486..4ac1a69a3b 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ import org.springframework.util.StringUtils; * @see RequestEntity * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class OAuth2ClientCredentialsGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverter.java index de08dd6fa9..b8f1d7f391 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ import org.springframework.util.StringUtils; * @see RequestEntity * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class OAuth2RefreshTokenGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverter.java index ea24499d30..142ef27225 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ import org.springframework.util.StringUtils; * 1.1 Delegation vs. Impersonation Semantics * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class TokenExchangeGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { From 9d442c13de5be1150b92fda1a88443853ec72495 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:14:23 -0500 Subject: [PATCH 034/504] Mark password grant for removal This commit also updates link to the document "Best Current Practice for OAuth 2.0 Security" to point to RFC 9700. Closes gh-16913 --- ...OAuth2AuthorizedClientProviderBuilder.java | 22 ++++++++--------- ...asswordOAuth2AuthorizedClientProvider.java | 12 +++++----- ...eactiveOAuth2AuthorizedClientProvider.java | 12 +++++----- ...OAuth2AuthorizedClientProviderBuilder.java | 24 +++++++++---------- .../DefaultPasswordTokenResponseClient.java | 12 +++++----- .../endpoint/OAuth2PasswordGrantRequest.java | 12 +++++----- ...h2PasswordGrantRequestEntityConverter.java | 4 ++-- ...ntReactivePasswordTokenResponseClient.java | 12 +++++----- .../oauth2/core/AuthorizationGrantType.java | 11 ++++----- 9 files changed, 58 insertions(+), 63 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java index 316b2d5c13..74026e7e56 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClientProviderBuilder.java @@ -138,13 +138,12 @@ public final class OAuth2AuthorizedClientProviderBuilder { /** * Configures support for the {@code password} grant. * @return the {@link OAuth2AuthorizedClientProviderBuilder} - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use - * of the Resource Owner Password Credentials grant. See reference - * OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ - @Deprecated + @Deprecated(since = "5.8", forRemoval = true) public OAuth2AuthorizedClientProviderBuilder password() { this.builders.computeIfAbsent(PasswordOAuth2AuthorizedClientProvider.class, (k) -> new PasswordGrantBuilder()); return OAuth2AuthorizedClientProviderBuilder.this; @@ -155,13 +154,12 @@ public final class OAuth2AuthorizedClientProviderBuilder { * @param builderConsumer a {@code Consumer} of {@link PasswordGrantBuilder} used for * further configuration * @return the {@link OAuth2AuthorizedClientProviderBuilder} - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use - * of the Resource Owner Password Credentials grant. See reference - * OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ - @Deprecated + @Deprecated(since = "5.8", forRemoval = true) public OAuth2AuthorizedClientProviderBuilder password(Consumer builderConsumer) { PasswordGrantBuilder builder = (PasswordGrantBuilder) this.builders .computeIfAbsent(PasswordOAuth2AuthorizedClientProvider.class, (k) -> new PasswordGrantBuilder()); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java index 04b12cd3f5..c3c80284af 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordOAuth2AuthorizedClientProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,12 +40,12 @@ import org.springframework.util.StringUtils; * @since 5.2 * @see OAuth2AuthorizedClientProvider * @see DefaultPasswordTokenResponseClient - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use of - * the Resource Owner Password Credentials grant. See reference OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ -@Deprecated +@Deprecated(since = "5.8", forRemoval = true) public final class PasswordOAuth2AuthorizedClientProvider implements OAuth2AuthorizedClientProvider { private OAuth2AccessTokenResponseClient accessTokenResponseClient = new DefaultPasswordTokenResponseClient(); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java index f83b9b338d..b3229a8b01 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/PasswordReactiveOAuth2AuthorizedClientProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,12 +40,12 @@ import org.springframework.util.StringUtils; * @since 5.2 * @see ReactiveOAuth2AuthorizedClientProvider * @see WebClientReactivePasswordTokenResponseClient - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use of - * the Resource Owner Password Credentials grant. See reference OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ -@Deprecated +@Deprecated(since = "5.8", forRemoval = true) public final class PasswordReactiveOAuth2AuthorizedClientProvider implements ReactiveOAuth2AuthorizedClientProvider { private ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient = new WebClientReactivePasswordTokenResponseClient(); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java index 3ad1d8bba9..f75de34304 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientProviderBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,13 +139,12 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { /** * Configures support for the {@code password} grant. * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use - * of the Resource Owner Password Credentials grant. See reference - * OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ - @Deprecated + @Deprecated(since = "5.8", forRemoval = true) public ReactiveOAuth2AuthorizedClientProviderBuilder password() { this.builders.computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, (k) -> new PasswordGrantBuilder()); @@ -157,13 +156,12 @@ public final class ReactiveOAuth2AuthorizedClientProviderBuilder { * @param builderConsumer a {@code Consumer} of {@link PasswordGrantBuilder} used for * further configuration * @return the {@link ReactiveOAuth2AuthorizedClientProviderBuilder} - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use - * of the Resource Owner Password Credentials grant. See reference - * OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ - @Deprecated + @Deprecated(since = "5.8", forRemoval = true) public ReactiveOAuth2AuthorizedClientProviderBuilder password(Consumer builderConsumer) { PasswordGrantBuilder builder = (PasswordGrantBuilder) this.builders .computeIfAbsent(PasswordReactiveOAuth2AuthorizedClientProvider.class, (k) -> new PasswordGrantBuilder()); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java index 0fd6145a34..8b27ec5a1a 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,12 +52,12 @@ import org.springframework.web.client.RestTemplate; * @see Section 4.3.3 Access Token Response * (Resource Owner Password Credentials Grant) - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use of - * the Resource Owner Password Credentials grant. See reference OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ -@Deprecated +@Deprecated(since = "5.8", forRemoval = true) public final class DefaultPasswordTokenResponseClient implements OAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequest.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequest.java index f192d8b1ec..48f78f8628 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequest.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,12 +35,12 @@ import org.springframework.util.StringUtils; * @see Section 1.3.3 Resource Owner * Password Credentials - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use of - * the Resource Owner Password Credentials grant. See reference OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ -@Deprecated +@Deprecated(since = "5.8", forRemoval = true) public class OAuth2PasswordGrantRequest extends AbstractOAuth2AuthorizationGrantRequest { private final String username; diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverter.java index 9d25da6e7e..1c0fc4aad9 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ import org.springframework.util.StringUtils; * @see RequestEntity * @deprecated Use {@link DefaultOAuth2TokenRequestParametersConverter} instead */ -@Deprecated(since = "6.4") +@Deprecated(since = "6.4", forRemoval = true) public class OAuth2PasswordGrantRequestEntityConverter extends AbstractOAuth2AuthorizationGrantRequestEntityConverter { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClient.java index 1de84db719..ff16eb855f 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactivePasswordTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,12 +37,12 @@ import org.springframework.web.reactive.function.client.WebClient; * @see Section 4.3.3 Access Token Response * (Resource Owner Password Credentials Grant) - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use of - * the Resource Owner Password Credentials grant. See reference OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ -@Deprecated +@Deprecated(since = "5.8", forRemoval = true) public final class WebClientReactivePasswordTokenResponseClient extends AbstractWebClientReactiveOAuth2AccessTokenResponseClient { diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java index ae8d054616..912af07729 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java @@ -48,13 +48,12 @@ public final class AuthorizationGrantType implements Serializable { public static final AuthorizationGrantType CLIENT_CREDENTIALS = new AuthorizationGrantType("client_credentials"); /** - * @deprecated The latest OAuth 2.0 Security Best Current Practice disallows the use - * of the Resource Owner Password Credentials grant. See reference - * OAuth - * 2.0 Security Best Current Practice. + * @deprecated The OAuth 2.0 Security Best Current Practice disallows the use of the + * Resource Owner Password Credentials grant. See reference OAuth 2.0 Security Best + * Current Practice. */ - @Deprecated + @Deprecated(since = "5.8", forRemoval = true) public static final AuthorizationGrantType PASSWORD = new AuthorizationGrantType("password"); /** From 43ef4262daa2906f970a237df50dff08bd2d305d Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:19:50 -0500 Subject: [PATCH 035/504] Update whats-new.adoc Issue gh-16913 --- docs/modules/ROOT/pages/whats-new.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index 03368827eb..b1bc5f72b1 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -18,6 +18,7 @@ Note that this may affect reports that operate on this key name. == OAuth * https://github.com/spring-projects/spring-security/pull/16386[gh-16386] - Enable PKCE for confidential clients using `ClientRegistration.clientSettings.requireProofKey=true` for xref:servlet/oauth2/client/core.adoc#oauth2Client-client-registration-requireProofKey[servlet] and xref:reactive/oauth2/client/core.adoc#oauth2Client-client-registration-requireProofKey[reactive] applications +* https://github.com/spring-projects/spring-security/issues/16913[gh-16913] - Prepare OAuth2 Client deprecations for removal in Spring Security 7 == WebAuthn From 9908d966448ca7416887ad44058913becece331c Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Wed, 9 Apr 2025 00:38:49 +0900 Subject: [PATCH 036/504] DeferredCsrfToken Implements Supplier Closes gh-16870 Signed-off-by: Daeho Kwon --- .../SessionManagementConfigurerServlet31Tests.java | 4 ++-- .../request/SecurityMockMvcRequestPostProcessors.java | 2 +- .../SecurityMockMvcRequestPostProcessorsCsrfTests.java | 2 +- .../security/web/csrf/CsrfAuthenticationStrategy.java | 4 ++-- .../org/springframework/security/web/csrf/CsrfFilter.java | 4 ++-- .../security/web/csrf/DeferredCsrfToken.java | 7 +++++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java index b17ce7635a..e5e129197d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,7 +87,7 @@ public class SessionManagementConfigurerServlet31Tests { HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); CsrfTokenRequestHandler handler = new XorCsrfTokenRequestAttributeHandler(); DeferredCsrfToken deferredCsrfToken = repository.loadDeferredToken(request, this.response); - handler.handle(request, this.response, deferredCsrfToken::get); + handler.handle(request, this.response, deferredCsrfToken); CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); request.setParameter(token.getParameterName(), token.getToken()); request.getSession().setAttribute("attribute1", "value1"); diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java index d17e7dda1f..29fe282fa2 100644 --- a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java +++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java @@ -524,7 +524,7 @@ public final class SecurityMockMvcRequestPostProcessors { TestCsrfTokenRepository.enable(request); MockHttpServletResponse response = new MockHttpServletResponse(); DeferredCsrfToken deferredCsrfToken = repository.loadDeferredToken(request, response); - handler.handle(request, response, deferredCsrfToken::get); + handler.handle(request, response, deferredCsrfToken); CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); String tokenValue = this.useInvalidToken ? INVALID_TOKEN_VALUE : token.getToken(); if (this.asHeader) { diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java index b5d0742a93..98e6f92057 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java @@ -164,7 +164,7 @@ public class SecurityMockMvcRequestPostProcessorsCsrfTests { HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository(); CsrfTokenRequestHandler handler = new XorCsrfTokenRequestAttributeHandler(); DeferredCsrfToken deferredCsrfToken = repo.loadDeferredToken(request, response); - handler.handle(request, response, deferredCsrfToken::get); + handler.handle(request, response, deferredCsrfToken); CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); MockHttpServletRequestBuilder requestWithCsrf = post("/") .param(token.getParameterName(), token.getToken()) diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfAuthenticationStrategy.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfAuthenticationStrategy.java index 5407d19bbb..f97c067a9b 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfAuthenticationStrategy.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfAuthenticationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -69,7 +69,7 @@ public final class CsrfAuthenticationStrategy implements SessionAuthenticationSt if (containsToken) { this.tokenRepository.saveToken(null, request, response); DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request, response); - this.requestHandler.handle(request, response, deferredCsrfToken::get); + this.requestHandler.handle(request, response, deferredCsrfToken); this.logger.debug("Replaced CSRF Token"); } } diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java index e6034b6bfb..2164675c74 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,7 +108,7 @@ public final class CsrfFilter extends OncePerRequestFilter { throws ServletException, IOException { DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request, response); request.setAttribute(DeferredCsrfToken.class.getName(), deferredCsrfToken); - this.requestHandler.handle(request, response, deferredCsrfToken::get); + this.requestHandler.handle(request, response, deferredCsrfToken); if (!this.requireCsrfProtectionMatcher.matches(request)) { if (this.logger.isTraceEnabled()) { this.logger.trace("Did not protect against CSRF since request did not match " diff --git a/web/src/main/java/org/springframework/security/web/csrf/DeferredCsrfToken.java b/web/src/main/java/org/springframework/security/web/csrf/DeferredCsrfToken.java index a27a31f7c1..c6c253f9dc 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/DeferredCsrfToken.java +++ b/web/src/main/java/org/springframework/security/web/csrf/DeferredCsrfToken.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,17 @@ package org.springframework.security.web.csrf; +import java.util.function.Supplier; + /** * An interface that allows delayed access to a {@link CsrfToken} that may be generated. * * @author Rob Winch * @author Steve Riesenberg + * @author Daeho Kwon * @since 5.8 */ -public interface DeferredCsrfToken { +public interface DeferredCsrfToken extends Supplier { /** * Gets the {@link CsrfToken} From 368fe2e7a00ec3e17026f6296d5513c2f8580f33 Mon Sep 17 00:00:00 2001 From: Risto Virtanen <818702+mapsu@users.noreply.github.com> Date: Wed, 26 Mar 2025 11:04:34 +0200 Subject: [PATCH 037/504] Add missing ClientAuthenticationMethods to jackson2 converter Closes gh-16825 Signed-off-by: Risto Virtanen <818702+mapsu@users.noreply.github.com> --- .../oauth2/client/jackson2/StdConverters.java | 14 ++- .../ClientRegistrationMixinTests.java | 112 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java index 4ce6223cf4..e6ee89668b 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,9 +56,21 @@ abstract class StdConverters { if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equalsIgnoreCase(value)) { return ClientAuthenticationMethod.CLIENT_SECRET_POST; } + if (ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue().equalsIgnoreCase(value)) { + return ClientAuthenticationMethod.CLIENT_SECRET_JWT; + } + if (ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue().equalsIgnoreCase(value)) { + return ClientAuthenticationMethod.PRIVATE_KEY_JWT; + } if (ClientAuthenticationMethod.NONE.getValue().equalsIgnoreCase(value)) { return ClientAuthenticationMethod.NONE; } + if (ClientAuthenticationMethod.TLS_CLIENT_AUTH.getValue().equalsIgnoreCase(value)) { + return ClientAuthenticationMethod.TLS_CLIENT_AUTH; + } + if (ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH.getValue().equalsIgnoreCase(value)) { + return ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH; + } return null; } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java new file mode 100644 index 0000000000..693abe7f46 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.jackson2; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ClientRegistrationMixinTests { + + private ObjectMapper mapper; + + @BeforeEach + void setUp() { + ClassLoader loader = getClass().getClassLoader(); + this.mapper = new ObjectMapper(); + this.mapper.registerModules(SecurityJackson2Modules.getModules(loader)); + } + + @ParameterizedTest + @MethodSource("deserializeWhenMixinRegisteredThenDeserializes") + void deserializeWhenMixinRegisteredThenDeserializes( + ClientRegistration expectedClientRegistration + ) throws Exception { + String json = asJson(expectedClientRegistration); + ClientRegistration clientRegistration = this.mapper.readValue(json, ClientRegistration.class); + assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(expectedClientRegistration.getClientAuthenticationMethod()); + } + + private String asJson(ClientRegistration expectedClientRegistration) { + // @formatter:off + return "{" + + " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration\"," + + " \"registrationId\":\"registration-id\"," + + " \"clientId\":\"client-id\"," + + " \"clientSecret\":\"client-secret\"," + + " \"clientAuthenticationMethod\":{" + + " \"value\":\"" + expectedClientRegistration.getClientAuthenticationMethod().getValue() + "\"" + + " }," + + " \"authorizationGrantType\":{" + + " \"value\":\"" + expectedClientRegistration.getAuthorizationGrantType().getValue() + "\"" + + " }," + + " \"redirectUri\":\"{baseUrl}/{action}/oauth2/code/{registrationId}\"," + + " \"scopes\":[" + + " \"java.util.Collections$UnmodifiableSet\",[\"read:user\"]" + + " ]," + + " \"providerDetails\":{" + + " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration$ProviderDetails\"," + + " \"authorizationUri\":\"https://example.com/login/oauth/authorize\"," + + " \"tokenUri\": \"https://example.com/login/oauth/access_token\"," + + " \"userInfoEndpoint\":{" + + " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration$ProviderDetails$UserInfoEndpoint\"," + + " \"uri\":\"https://api.example.com/user\"," + + " \"authenticationMethod\":{" + + " \"value\":\"header\"" + + " }," + + " \"userNameAttributeName\":\"id\"" + + " }," + + " \"jwkSetUri\":\"https://example.com/oauth2/jwk\"," + + " \"issuerUri\":\"https://example.com\"," + + " \"configurationMetadata\":{" + + " \"@class\":\"java.util.Collections$UnmodifiableMap\"" + + " }" + + " }," + + " \"clientName\":\"Client Name\"}"; + // @formatter:on + } + + static Stream deserializeWhenMixinRegisteredThenDeserializes() { + return Stream.of( + Arguments.of( + TestClientRegistrations.clientRegistration() + .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) + .build() + ), + Arguments.of( + TestClientRegistrations.clientRegistration() + .clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT) + .build() + ), + Arguments.of( + TestClientRegistrations.clientRegistration() + .clientAuthenticationMethod(ClientAuthenticationMethod.NONE) + .build() + ) + ); + } +} From 1db557e395a37afe1a6aed6fe5845aefb2f43bee Mon Sep 17 00:00:00 2001 From: Risto Virtanen <818702+mapsu@users.noreply.github.com> Date: Fri, 4 Apr 2025 21:24:50 +0300 Subject: [PATCH 038/504] Replace ClientRegistrationMixinTests with StdConvertersTest Signed-off-by: Risto Virtanen <818702+mapsu@users.noreply.github.com> --- .../oauth2/client/jackson2/StdConverters.java | 23 +--- .../ClientRegistrationMixinTests.java | 112 ------------------ .../client/jackson2/StdConvertersTest.java | 56 +++++++++ 3 files changed, 57 insertions(+), 134 deletions(-) delete mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java index e6ee89668b..b544f26793 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/jackson2/StdConverters.java @@ -50,28 +50,7 @@ abstract class StdConverters { @Override public ClientAuthenticationMethod convert(JsonNode jsonNode) { String value = JsonNodeUtils.findStringValue(jsonNode, "value"); - if (ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.CLIENT_SECRET_BASIC; - } - if (ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.CLIENT_SECRET_POST; - } - if (ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.CLIENT_SECRET_JWT; - } - if (ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.PRIVATE_KEY_JWT; - } - if (ClientAuthenticationMethod.NONE.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.NONE; - } - if (ClientAuthenticationMethod.TLS_CLIENT_AUTH.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.TLS_CLIENT_AUTH; - } - if (ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH.getValue().equalsIgnoreCase(value)) { - return ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH; - } - return null; + return ClientAuthenticationMethod.valueOf(value); } } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java deleted file mode 100644 index 693abe7f46..0000000000 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/ClientRegistrationMixinTests.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.oauth2.client.jackson2; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.security.jackson2.SecurityJackson2Modules; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.TestClientRegistrations; -import org.springframework.security.oauth2.core.ClientAuthenticationMethod; - -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ClientRegistrationMixinTests { - - private ObjectMapper mapper; - - @BeforeEach - void setUp() { - ClassLoader loader = getClass().getClassLoader(); - this.mapper = new ObjectMapper(); - this.mapper.registerModules(SecurityJackson2Modules.getModules(loader)); - } - - @ParameterizedTest - @MethodSource("deserializeWhenMixinRegisteredThenDeserializes") - void deserializeWhenMixinRegisteredThenDeserializes( - ClientRegistration expectedClientRegistration - ) throws Exception { - String json = asJson(expectedClientRegistration); - ClientRegistration clientRegistration = this.mapper.readValue(json, ClientRegistration.class); - assertThat(clientRegistration.getClientAuthenticationMethod()).isEqualTo(expectedClientRegistration.getClientAuthenticationMethod()); - } - - private String asJson(ClientRegistration expectedClientRegistration) { - // @formatter:off - return "{" + - " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration\"," + - " \"registrationId\":\"registration-id\"," + - " \"clientId\":\"client-id\"," + - " \"clientSecret\":\"client-secret\"," + - " \"clientAuthenticationMethod\":{" + - " \"value\":\"" + expectedClientRegistration.getClientAuthenticationMethod().getValue() + "\"" + - " }," + - " \"authorizationGrantType\":{" + - " \"value\":\"" + expectedClientRegistration.getAuthorizationGrantType().getValue() + "\"" + - " }," + - " \"redirectUri\":\"{baseUrl}/{action}/oauth2/code/{registrationId}\"," + - " \"scopes\":[" + - " \"java.util.Collections$UnmodifiableSet\",[\"read:user\"]" + - " ]," + - " \"providerDetails\":{" + - " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration$ProviderDetails\"," + - " \"authorizationUri\":\"https://example.com/login/oauth/authorize\"," + - " \"tokenUri\": \"https://example.com/login/oauth/access_token\"," + - " \"userInfoEndpoint\":{" + - " \"@class\":\"org.springframework.security.oauth2.client.registration.ClientRegistration$ProviderDetails$UserInfoEndpoint\"," + - " \"uri\":\"https://api.example.com/user\"," + - " \"authenticationMethod\":{" + - " \"value\":\"header\"" + - " }," + - " \"userNameAttributeName\":\"id\"" + - " }," + - " \"jwkSetUri\":\"https://example.com/oauth2/jwk\"," + - " \"issuerUri\":\"https://example.com\"," + - " \"configurationMetadata\":{" + - " \"@class\":\"java.util.Collections$UnmodifiableMap\"" + - " }" + - " }," + - " \"clientName\":\"Client Name\"}"; - // @formatter:on - } - - static Stream deserializeWhenMixinRegisteredThenDeserializes() { - return Stream.of( - Arguments.of( - TestClientRegistrations.clientRegistration() - .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST) - .build() - ), - Arguments.of( - TestClientRegistrations.clientRegistration() - .clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT) - .build() - ), - Arguments.of( - TestClientRegistrations.clientRegistration() - .clientAuthenticationMethod(ClientAuthenticationMethod.NONE) - .build() - ) - ); - } -} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java new file mode 100644 index 0000000000..428413e154 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.jackson2; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.util.StdConverter; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StdConvertersTest { + + private final StdConverter clientAuthenticationMethodConverter = + new StdConverters.ClientAuthenticationMethodConverter(); + + @ParameterizedTest + @MethodSource("testClientAuthenticationMethodConverting") + void testClientAuthenticationMethodConverting(String clientAuthenticationMethod) { + ObjectNode jsonNode = JsonNodeFactory.instance.objectNode(); + jsonNode.put("value", clientAuthenticationMethod); + ClientAuthenticationMethod actual = this.clientAuthenticationMethodConverter.convert(jsonNode); + assertEquals(clientAuthenticationMethod, actual.getValue()); + + } + + static Stream testClientAuthenticationMethodConverting() { + return Stream.of( + Arguments.of(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()), + Arguments.of(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue()), + Arguments.of(ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue()), + Arguments.of(ClientAuthenticationMethod.NONE.getValue()), + Arguments.of("custom_method") + ); + } +} From 47e1fc045fb81730809d296f54d5025aaaa845b4 Mon Sep 17 00:00:00 2001 From: Risto Virtanen <818702+mapsu@users.noreply.github.com> Date: Tue, 8 Apr 2025 19:52:57 +0300 Subject: [PATCH 039/504] Formatted Signed-off-by: Risto Virtanen <818702+mapsu@users.noreply.github.com> --- ...rtersTest.java => StdConvertersTests.java} | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) rename oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/{StdConvertersTest.java => StdConvertersTests.java} (69%) diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTests.java similarity index 69% rename from oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java rename to oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTests.java index 428413e154..2cee9a1b54 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTest.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/jackson2/StdConvertersTests.java @@ -16,6 +16,8 @@ package org.springframework.security.oauth2.client.jackson2; +import java.util.stream.Stream; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -23,34 +25,29 @@ import com.fasterxml.jackson.databind.util.StdConverter; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; + import org.springframework.security.oauth2.core.ClientAuthenticationMethod; -import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +public class StdConvertersTests { -public class StdConvertersTest { - - private final StdConverter clientAuthenticationMethodConverter = - new StdConverters.ClientAuthenticationMethodConverter(); + private final StdConverter clientAuthenticationMethodConverter = new StdConverters.ClientAuthenticationMethodConverter(); @ParameterizedTest - @MethodSource("testClientAuthenticationMethodConverting") - void testClientAuthenticationMethodConverting(String clientAuthenticationMethod) { + @MethodSource("convertWhenClientAuthenticationMethodConvertedThenDeserializes") + void convertWhenClientAuthenticationMethodConvertedThenDeserializes(String clientAuthenticationMethod) { ObjectNode jsonNode = JsonNodeFactory.instance.objectNode(); jsonNode.put("value", clientAuthenticationMethod); ClientAuthenticationMethod actual = this.clientAuthenticationMethodConverter.convert(jsonNode); - assertEquals(clientAuthenticationMethod, actual.getValue()); - + assertThat(actual.getValue()).isEqualTo(clientAuthenticationMethod); } - static Stream testClientAuthenticationMethodConverting() { - return Stream.of( - Arguments.of(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()), + static Stream convertWhenClientAuthenticationMethodConvertedThenDeserializes() { + return Stream.of(Arguments.of(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()), Arguments.of(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue()), Arguments.of(ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue()), - Arguments.of(ClientAuthenticationMethod.NONE.getValue()), - Arguments.of("custom_method") - ); + Arguments.of(ClientAuthenticationMethod.NONE.getValue()), Arguments.of("custom_method")); } + } From 3e686abf50da71b5f00aefb2a37f425b201c804f Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:24:00 -0600 Subject: [PATCH 040/504] Add ResponseValidator Issue gh-14264 Closes gh-16915 --- .../servlet/saml2/login/authentication.adoc | 24 +++ .../BaseOpenSamlAuthenticationProvider.java | 6 +- .../OpenSaml5AuthenticationProvider.java | 139 +++++++++++++++++- .../OpenSaml5AuthenticationProviderTests.java | 17 +++ 4 files changed, 179 insertions(+), 7 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index 9fc64c2638..f4feb3c1f6 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -359,6 +359,30 @@ provider.setResponseValidator((responseToken) -> { }); ---- +When using `OpenSaml5AuthenticationProvider`, you can do the same with less boilerplate: + +[source,java] +---- +OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); +ResponseValidator responseValidator = ResponseValidator.withDefaults(myCustomValidator); +provider.setResponseValidator(responseValidator); +---- + +You can also customize which validation steps Spring Security should do. +For example, if you want to skip `Response#InResponseTo` validation, you can call ``ResponseValidator``'s constructor, excluding `InResponseToValidator` from the list: + +[source,java] +---- +OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); +ResponseValidator responseValidator = new ResponseValidator(new DestinationValidator(), new IssuerValidator()); +provider.setResponseValidator(responseValidator); +---- + +[TIP] +==== +OpenSAML performs `Asssertion#InResponseTo` validation in its `BearerSubjectConfirmationValidator` class, which is configurable using <<_performing_additional_assertion_validation, setAssertionValidator>>. +==== + == Performing Additional Assertion Validation `OpenSaml4AuthenticationProvider` performs minimal validation on SAML 2.0 Assertions. After verifying the signature, it will: diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java index 5199f43af9..e0a0d3a6e7 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java @@ -183,7 +183,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { }; } - private static List getStatusCodes(Response response) { + static List getStatusCodes(Response response) { if (response.getStatus() == null) { return List.of(StatusCode.SUCCESS); } @@ -206,7 +206,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return List.of(parentStatusCodeValue, childStatusCodeValue); } - private static boolean isSuccess(List statusCodes) { + static boolean isSuccess(List statusCodes) { if (statusCodes.size() != 1) { return false; } @@ -215,7 +215,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return StatusCode.SUCCESS.equals(statusCode); } - private static Saml2ResponseValidatorResult validateInResponseTo(AbstractSaml2AuthenticationRequest storedRequest, + static Saml2ResponseValidatorResult validateInResponseTo(AbstractSaml2AuthenticationRequest storedRequest, String inResponseTo) { if (!StringUtils.hasText(inResponseTo)) { return Saml2ResponseValidatorResult.success(); diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java index f6ca75e1cc..985797de23 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java @@ -53,6 +53,7 @@ import org.opensaml.xmlsec.signature.support.SignaturePrevalidator; import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.NonNull; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; @@ -60,6 +61,7 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; +import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -114,6 +116,7 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv */ public OpenSaml5AuthenticationProvider() { this.delegate = new BaseOpenSamlAuthenticationProvider(new OpenSaml5Template()); + setResponseValidator(ResponseValidator.withDefaults()); setAssertionValidator(AssertionValidator.withDefaults()); } @@ -301,12 +304,11 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * Construct a default strategy for validating the SAML 2.0 Response * @return the default response validator strategy * @since 5.6 + * @deprecated please use {@link ResponseValidator#withDefaults()} instead */ + @Deprecated public static Converter createDefaultResponseValidator() { - Converter delegate = BaseOpenSamlAuthenticationProvider - .createDefaultResponseValidator(); - return (token) -> delegate - .convert(new BaseOpenSamlAuthenticationProvider.ResponseToken(token.getResponse(), token.getToken())); + return ResponseValidator.withDefaults(); } /** @@ -459,6 +461,135 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv } + /** + * A response validator that checks the {@code InResponseTo} value against the + * correlating {@link AbstractSaml2AuthenticationRequest} + * + * @since 6.5 + */ + public static final class InResponseToValidator implements Converter { + + @Override + @NonNull + public Saml2ResponseValidatorResult convert(ResponseToken responseToken) { + AbstractSaml2AuthenticationRequest request = responseToken.getToken().getAuthenticationRequest(); + Response response = responseToken.getResponse(); + String inResponseTo = response.getInResponseTo(); + return BaseOpenSamlAuthenticationProvider.validateInResponseTo(request, inResponseTo); + } + + } + + /** + * A response validator that compares the {@code Destination} value to the configured + * {@link RelyingPartyRegistration#getAssertionConsumerServiceLocation()} + * + * @since 6.5 + */ + public static final class DestinationValidator implements Converter { + + @Override + @NonNull + public Saml2ResponseValidatorResult convert(ResponseToken responseToken) { + Response response = responseToken.getResponse(); + Saml2AuthenticationToken token = responseToken.getToken(); + String destination = response.getDestination(); + String location = token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation(); + if (StringUtils.hasText(destination) && !destination.equals(location)) { + String message = "Invalid destination [" + destination + "] for SAML response [" + response.getID() + + "]"; + return Saml2ResponseValidatorResult + .failure(new Saml2Error(Saml2ErrorCodes.INVALID_DESTINATION, message)); + } + return Saml2ResponseValidatorResult.success(); + } + + } + + /** + * A response validator that compares the {@code Issuer} value to the configured + * {@link AssertingPartyMetadata#getEntityId()} + * + * @since 6.5 + */ + public static final class IssuerValidator implements Converter { + + @Override + @NonNull + public Saml2ResponseValidatorResult convert(ResponseToken responseToken) { + Response response = responseToken.getResponse(); + Saml2AuthenticationToken token = responseToken.getToken(); + String issuer = response.getIssuer().getValue(); + String assertingPartyEntityId = token.getRelyingPartyRegistration() + .getAssertingPartyMetadata() + .getEntityId(); + if (!StringUtils.hasText(issuer) || !issuer.equals(assertingPartyEntityId)) { + String message = String.format("Invalid issuer [%s] for SAML response [%s]", issuer, response.getID()); + return Saml2ResponseValidatorResult.failure(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, message)); + } + return Saml2ResponseValidatorResult.success(); + } + + } + + /** + * A composite response validator that confirms a {@code SUCCESS} status, that there + * is at least one assertion, and any other configured converters + * + * @since 6.5 + * @see InResponseToValidator + * @see DestinationValidator + * @see IssuerValidator + */ + public static final class ResponseValidator implements Converter { + + private static final List> DEFAULTS = List + .of(new InResponseToValidator(), new DestinationValidator(), new IssuerValidator()); + + private final List> validators; + + @SafeVarargs + public ResponseValidator(Converter... validators) { + this.validators = List.of(validators); + Assert.notEmpty(this.validators, "validators cannot be empty"); + } + + public static ResponseValidator withDefaults() { + return new ResponseValidator(new InResponseToValidator(), new DestinationValidator(), + new IssuerValidator()); + } + + @SafeVarargs + public static ResponseValidator withDefaults( + Converter... validators) { + List> defaults = new ArrayList<>(DEFAULTS); + defaults.addAll(List.of(validators)); + return new ResponseValidator(defaults.toArray(Converter[]::new)); + } + + @Override + public Saml2ResponseValidatorResult convert(ResponseToken responseToken) { + Response response = responseToken.getResponse(); + Collection errors = new ArrayList<>(); + List statusCodes = BaseOpenSamlAuthenticationProvider.getStatusCodes(response); + if (!BaseOpenSamlAuthenticationProvider.isSuccess(statusCodes)) { + for (String statusCode : statusCodes) { + String message = String.format("Invalid status [%s] for SAML response [%s]", statusCode, + response.getID()); + errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, message)); + } + } + for (Converter validator : this.validators) { + errors.addAll(validator.convert(responseToken).getErrors()); + } + if (response.getAssertions().isEmpty()) { + errors.add(new Saml2Error(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, "No assertions found in response.")); + } + return Saml2ResponseValidatorResult.failure(errors); + } + + } + /** * A default implementation of {@link OpenSaml5AuthenticationProvider}'s assertion * validator. This does not check the signature as signature verification is performed diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index a0ef0de8cf..3c324875a9 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -78,6 +78,7 @@ import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; import org.springframework.security.saml2.core.TestSaml2X509Credentials; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.AssertionValidator; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseToken; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseValidator; import org.springframework.security.saml2.provider.service.authentication.TestCustomOpenSaml5Objects.CustomOpenSamlObject; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; @@ -754,6 +755,22 @@ public class OpenSaml5AuthenticationProviderTests { verify(validator).convert(any(OpenSaml5AuthenticationProvider.ResponseToken.class)); } + @Test + public void authenticateWhenCustomSetOfResponseValidatorsThenUses() { + Converter validator = mock( + Converter.class); + given(validator.convert(any())) + .willReturn(Saml2ResponseValidatorResult.failure(new Saml2Error("error", "description"))); + ResponseValidator responseValidator = new ResponseValidator(validator); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setResponseValidator(responseValidator); + Response response = TestOpenSamlObjects.signedResponseWithOneAssertion(); + Saml2AuthenticationToken token = token(response, verifying(registration())); + assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token)) + .withMessageContaining("description"); + verify(validator).convert(any()); + } + @Test public void authenticateWhenResponseStatusIsNotSuccessThenOnlyReturnParentStatusCodes() { Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.token(); From 3869b13e682c98370e2766eaba7a4d56d0159dff Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:35:28 -0600 Subject: [PATCH 041/504] Add ResponseAuthenticationConverter Aside from simplifying configuration, this commit also makes it possible to provide a response authentication converter that doesn't need the NameID element to be present. Closes gh-12136 --- .../modules/ROOT/pages/migration-7/saml2.adoc | 105 ++++++++++ .../servlet/saml2/login/authentication.adoc | 195 ++++++++++++++++++ .../ROOT/pages/servlet/saml2/logout.adoc | 4 +- .../BaseOpenSamlAuthenticationProvider.java | 31 ++- .../OpenSaml4AuthenticationProvider.java | 1 + .../OpenSaml5AuthenticationProvider.java | 103 ++++++++- .../OpenSaml5AuthenticationProviderTests.java | 46 +++++ 7 files changed, 470 insertions(+), 15 deletions(-) diff --git a/docs/modules/ROOT/pages/migration-7/saml2.adoc b/docs/modules/ROOT/pages/migration-7/saml2.adoc index 9a8cb60080..eed236a64b 100644 --- a/docs/modules/ROOT/pages/migration-7/saml2.adoc +++ b/docs/modules/ROOT/pages/migration-7/saml2.adoc @@ -58,3 +58,108 @@ Xml:: ---- ====== + +== 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/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index f4feb3c1f6..1c517914dc 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -250,12 +250,135 @@ class SecurityConfig { ---- ====== +== Converting an `Assertion` into an `Authentication` + +`OpenSamlXAuthenticationProvider#setResponseAuthenticationConverter` provides a way for you to change how it converts your assertion into an `Authentication` instance. + +You can set a custom converter in the following way: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Configuration +@EnableWebSecurity +public class SecurityConfig { + @Autowired + Converter authenticationConverter; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + OpenSaml5AuthenticationProvider authenticationProvider = new OpenSaml5AuthenticationProvider(); + authenticationProvider.setResponseAuthenticationConverter(this.authenticationConverter); + + http + .authorizeHttpRequests((authz) -> authz + .anyRequest().authenticated()) + .saml2Login((saml2) -> saml2 + .authenticationManager(new ProviderManager(authenticationProvider)) + ); + return http.build(); + } + +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Configuration +@EnableWebSecurity +open class SecurityConfig { + @Autowired + var authenticationConverter: Converter? = null + + @Bean + open fun filterChain(http: HttpSecurity): SecurityFilterChain { + val authenticationProvider = OpenSaml5AuthenticationProvider() + authenticationProvider.setResponseAuthenticationConverter(this.authenticationConverter) + http { + authorizeRequests { + authorize(anyRequest, authenticated) + } + saml2Login { + authenticationManager = ProviderManager(authenticationProvider) + } + } + return http.build() + } +} +---- +====== + +The ensuing examples all build off of this common construct to show you different ways this converter comes in handy. + [[servlet-saml2login-opensamlauthenticationprovider-userdetailsservice]] == Coordinating with a `UserDetailsService` Or, perhaps you would like to include user details from a legacy `UserDetailsService`. In that case, the response authentication converter can come in handy, as can be seen below: +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Component +class MyUserDetailsResponseAuthenticationConverter implements Converter { + private final ResponseAuthenticationConverter delegate = new ResponseAuthenticationConverter(); + private final UserDetailsService userDetailsService; + + MyUserDetailsResponseAuthenticationConverter(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + @Override + public Saml2Authentication convert(ResponseToken responseToken) { + Saml2Authentication authentication = this.delegate.convert(responseToken); <1> + UserDetails principal = this.userDetailsService.loadByUsername(username); <2> + String saml2Response = authentication.getSaml2Response(); + Collection authorities = principal.getAuthorities(); + return new Saml2Authentication((AuthenticatedPrincipal) userDetails, saml2Response, authorities); <3> + } + +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Component +open class MyUserDetailsResponseAuthenticationConverter(val delegate: ResponseAuthenticationConverter, + UserDetailsService userDetailsService): Converter { + + @Override + open fun convert(responseToken: ResponseToken): Saml2Authentication { + val authentication = this.delegate.convert(responseToken) <1> + val principal = this.userDetailsService.loadByUsername(username) <2> + val saml2Response = authentication.getSaml2Response() + val authorities = principal.getAuthorities() + return Saml2Authentication(userDetails as AuthenticatedPrincipal, saml2Response, authorities) <3> + } + +} +---- +====== +<1> First, call the default converter, which extracts attributes and authorities from the response +<2> Second, call the xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[`UserDetailsService`] using the relevant information +<3> Third, return an authentication that includes the user details + +[TIP] +==== +If your `UserDetailsService` returns a value that also implements `AuthenticatedPrincipal`, then you don't need a custom authentication implementation. +==== + +Or, if you are using OpenSaml 4, then you can achieve something similar as follows: + [tabs] ====== Java:: @@ -336,6 +459,78 @@ open class SecurityConfig { It's not required to call ``OpenSaml4AuthenticationProvider``'s default authentication converter. It returns a `Saml2AuthenticatedPrincipal` containing the attributes it extracted from ``AttributeStatement``s as well as the single `ROLE_USER` authority. +=== Configuring the Principal Name + +Sometimes, the principal name is not in the `` element. +In that case, you can configure the `ResponseAuthenticationConverter` with a custom strategy like so: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +ResponseAuthenticationConverter authenticationConverter() { + ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter(); + authenticationConverter.setPrincipalNameConverter((assertion) -> { + // ... work with OpenSAML's Assertion object to extract the principal + }); + return authenticationConverter; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationConverter(): ResponseAuthenticationConverter { + val authenticationConverter: ResponseAuthenticationConverter = ResponseAuthenticationConverter() + authenticationConverter.setPrincipalNameConverter { assertion -> + // ... work with OpenSAML's Assertion object to extract the principal + } + return authenticationConverter +} +---- +====== + +=== Configuring a Principal's Granted Authorities + +Spring Security automatically grants `ROLE_USER` when using `OpenSamlXAuhenticationProvider`. +With `OpenSaml5AuthenticationProvider`, you can configure a different set of granted authorities like so: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +ResponseAuthenticationConverter authenticationConverter() { + ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter(); + authenticationConverter.setPrincipalNameConverter((assertion) -> { + // ... grant the needed authorities based on attributes in the assertion + }); + return authenticationConverter; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationConverter(): ResponseAuthenticationConverter { + val authenticationConverter = ResponseAuthenticationConverter() + authenticationConverter.setPrincipalNameConverter{ assertion -> + // ... grant the needed authorities based on attributes in the assertion + } + return authenticationConverter +} +---- +====== + [[servlet-saml2login-opensamlauthenticationprovider-additionalvalidation]] == Performing Additional Response Validation diff --git a/docs/modules/ROOT/pages/servlet/saml2/logout.adoc b/docs/modules/ROOT/pages/servlet/saml2/logout.adoc index 03e7bb153e..edac04e737 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/logout.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/logout.adoc @@ -339,7 +339,7 @@ It's common to need to set other values in the `` than the By default, Spring Security will issue a `` and supply: -* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceLocation` +* The `DestinationValidator` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceLocation` * The `ID` attribute - a GUID * The `` element - from `RelyingPartyRegistration#getEntityId` * The `` element - from `Authentication#getName` @@ -424,7 +424,7 @@ It's common to need to set other values in the `` than the By default, Spring Security will issue a `` and supply: -* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceResponseLocation` +* The `DestinationValidator` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceResponseLocation` * The `ID` attribute - a GUID * The `` element - from `RelyingPartyRegistration#getEntityId` * The `` element - `SUCCESS` diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java index e0a0d3a6e7..2aba4d78a1 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java @@ -110,6 +110,8 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { private Converter responseAuthenticationConverter = createDefaultResponseAuthenticationConverter(); + private boolean validateResponseAfterAssertions = false; + private static final Set includeChildStatusCodes = new HashSet<>( Arrays.asList(StatusCode.REQUESTER, StatusCode.RESPONDER, StatusCode.VERSION_MISMATCH)); @@ -143,6 +145,10 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { this.responseAuthenticationConverter = responseAuthenticationConverter; } + void setValidateResponseAfterAssertions(boolean validateResponseAfterAssertions) { + this.validateResponseAfterAssertions = validateResponseAfterAssertions; + } + static Converter createDefaultResponseValidator() { return (responseToken) -> { Response response = responseToken.getResponse(); @@ -321,7 +327,9 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE, "Did not decrypt response [" + response.getID() + "] since it is not signed")); } - result = result.concat(this.responseValidator.convert(responseToken)); + if (!this.validateResponseAfterAssertions) { + result = result.concat(this.responseValidator.convert(responseToken)); + } boolean allAssertionsSigned = true; for (Assertion assertion : response.getAssertions()) { AssertionToken assertionToken = new AssertionToken(assertion, token); @@ -337,11 +345,16 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { + "Please either sign the response or all of the assertions."; result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE, description)); } - Assertion firstAssertion = CollectionUtils.firstElement(response.getAssertions()); - if (firstAssertion != null && !hasName(firstAssertion)) { - Saml2Error error = new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, - "Assertion [" + firstAssertion.getID() + "] is missing a subject"); - result = result.concat(error); + if (this.validateResponseAfterAssertions) { + result = result.concat(this.responseValidator.convert(responseToken)); + } + else { + Assertion firstAssertion = CollectionUtils.firstElement(response.getAssertions()); + if (firstAssertion != null && !hasName(firstAssertion)) { + Saml2Error error = new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, + "Assertion [" + firstAssertion.getID() + "] is missing a subject"); + result = result.concat(error); + } } if (result.hasErrors()) { @@ -422,7 +435,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { }; } - private boolean hasName(Assertion assertion) { + static boolean hasName(Assertion assertion) { if (assertion == null) { return false; } @@ -435,7 +448,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return assertion.getSubject().getNameID().getValue() != null; } - private static Map> getAssertionAttributes(Assertion assertion) { + static Map> getAssertionAttributes(Assertion assertion) { MultiValueMap attributeMap = new LinkedMultiValueMap<>(); for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) { for (Attribute attribute : attributeStatement.getAttributes()) { @@ -452,7 +465,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return new LinkedHashMap<>(attributeMap); // gh-11785 } - private static List getSessionIndexes(Assertion assertion) { + static List getSessionIndexes(Assertion assertion) { List sessionIndexes = new ArrayList<>(); for (AuthnStatement statement : assertion.getAuthnStatements()) { sessionIndexes.add(statement.getSessionIndex()); diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index b0eede6742..f1509a560d 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -85,6 +85,7 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv */ public OpenSaml4AuthenticationProvider() { this.delegate = new BaseOpenSamlAuthenticationProvider(new OpenSaml4Template()); + this.delegate.setValidateResponseAfterAssertions(false); } /** diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java index 985797de23..e3cde7974e 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java @@ -58,12 +58,15 @@ import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** @@ -118,6 +121,7 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv this.delegate = new BaseOpenSamlAuthenticationProvider(new OpenSaml5Template()); setResponseValidator(ResponseValidator.withDefaults()); setAssertionValidator(AssertionValidator.withDefaults()); + setResponseAuthenticationConverter(new ResponseAuthenticationConverter()); } /** @@ -300,6 +304,21 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv (token) -> responseAuthenticationConverter.convert(new ResponseToken(token))); } + /** + * Indicate when to validate response attributes, like {@code Destination} and + * {@code Issuer}. By default, this value is set to false, meaning that response + * attributes are validated first. Setting this value to {@code true} allows you to + * use a response authentication converter that doesn't rely on the {@code NameID} + * element in the {@link Response}'s assertion. + * @param validateResponseAfterAssertions when to validate response attributes + * @since 6.5 + * @see #setResponseAuthenticationConverter + * @see ResponseAuthenticationConverter + */ + public void setValidateResponseAfterAssertions(boolean validateResponseAfterAssertions) { + this.delegate.setValidateResponseAfterAssertions(validateResponseAfterAssertions); + } + /** * Construct a default strategy for validating the SAML 2.0 Response * @return the default response validator strategy @@ -373,12 +392,11 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv * Construct a default strategy for converting a SAML 2.0 Response and * {@link Authentication} token into a {@link Saml2Authentication} * @return the default response authentication converter strategy + * @deprecated please use {@link ResponseAuthenticationConverter} instead */ + @Deprecated public static Converter createDefaultResponseAuthenticationConverter() { - Converter delegate = BaseOpenSamlAuthenticationProvider - .createDefaultResponseAuthenticationConverter(); - return (token) -> delegate - .convert(new BaseOpenSamlAuthenticationProvider.ResponseToken(token.getResponse(), token.getToken())); + return new ResponseAuthenticationConverter(); } /** @@ -852,4 +870,81 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv } + /** + * A default implementation of {@link OpenSaml5AuthenticationProvider}'s response + * authentication converter. It will take the principal name from the + * {@link org.opensaml.saml.saml2.core.NameID} element. It will also extract the + * assertion attributes and session indexes. You can either configure the principal + * name converter and granted authorities converter in this class or you can + * post-process this class's result through delegation. + * + * @author Josh Cummings + * @since 6.5 + */ + public static final class ResponseAuthenticationConverter implements Converter { + + private Converter principalNameConverter = ResponseAuthenticationConverter::authenticatedPrincipal; + + private Converter> grantedAuthoritiesConverter = ResponseAuthenticationConverter::grantedAuthorities; + + @Override + public Saml2Authentication convert(ResponseToken responseToken) { + Response response = responseToken.response; + Saml2AuthenticationToken token = responseToken.token; + Assertion assertion = CollectionUtils.firstElement(response.getAssertions()); + String username = this.principalNameConverter.convert(assertion); + Map> attributes = BaseOpenSamlAuthenticationProvider.getAssertionAttributes(assertion); + List sessionIndexes = BaseOpenSamlAuthenticationProvider.getSessionIndexes(assertion); + DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes, + sessionIndexes); + String registrationId = responseToken.token.getRelyingPartyRegistration().getRegistrationId(); + principal.setRelyingPartyRegistrationId(registrationId); + return new Saml2Authentication(principal, token.getSaml2Response(), + this.grantedAuthoritiesConverter.convert(assertion)); + } + + /** + * Use this strategy to extract the principal name from the {@link Assertion}. By + * default, this will retrieve it from the + * {@link org.opensaml.saml.saml2.core.Subject}'s + * {@link org.opensaml.saml.saml2.core.NameID} value. + * + *

+ * Note that because of this, if there is no + * {@link org.opensaml.saml.saml2.core.NameID} present, then the default throws an + * exception. + *

+ * @param principalNameConverter the conversion strategy to use + */ + public void setPrincipalNameConverter(Converter principalNameConverter) { + Assert.notNull(principalNameConverter, "principalNameConverter cannot be null"); + this.principalNameConverter = principalNameConverter; + } + + /** + * Use this strategy to grant authorities to a principal given the first + * {@link Assertion} in the response. By default, this will grant + * {@code ROLE_USER}. + * @param grantedAuthoritiesConverter the conversion strategy to use + */ + public void setGrantedAuthoritiesConverter( + Converter> grantedAuthoritiesConverter) { + Assert.notNull(grantedAuthoritiesConverter, "grantedAuthoritiesConverter cannot be null"); + this.grantedAuthoritiesConverter = grantedAuthoritiesConverter; + } + + private static String authenticatedPrincipal(Assertion assertion) { + if (!BaseOpenSamlAuthenticationProvider.hasName(assertion)) { + throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, + "Assertion [" + assertion.getID() + "] is missing a subject")); + } + return assertion.getSubject().getNameID().getValue(); + } + + private static Collection grantedAuthorities(Assertion assertion) { + return AuthorityUtils.createAuthorityList("ROLE_USER"); + } + + } + } diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index 3c324875a9..071a8af128 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -22,6 +22,7 @@ import java.io.ObjectOutputStream; import java.time.Duration; import java.time.Instant; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -71,12 +72,15 @@ import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; import org.springframework.security.saml2.core.TestSaml2X509Credentials; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.AssertionValidator; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseAuthenticationConverter; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseToken; import org.springframework.security.saml2.provider.service.authentication.OpenSaml5AuthenticationProvider.ResponseValidator; import org.springframework.security.saml2.provider.service.authentication.TestCustomOpenSaml5Objects.CustomOpenSamlObject; @@ -92,6 +96,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; /** * Tests for {@link OpenSaml5AuthenticationProvider} @@ -660,6 +665,47 @@ public class OpenSaml5AuthenticationProviderTests { verify(authenticationConverter).convert(any()); } + @Test + public void authenticateWhenResponseAuthenticationConverterComponentConfiguredThenUses() { + Converter> grantedAuthoritiesConverter = mock(Converter.class); + given(grantedAuthoritiesConverter.convert(any())).willReturn(AuthorityUtils.createAuthorityList("CUSTOM")); + ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter(); + authenticationConverter.setGrantedAuthoritiesConverter(grantedAuthoritiesConverter); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setResponseAuthenticationConverter(authenticationConverter); + Response response = TestOpenSamlObjects.signedResponseWithOneAssertion(); + Saml2AuthenticationToken token = token(response, verifying(registration())); + Authentication authentication = provider.authenticate(token); + assertThat(AuthorityUtils.authorityListToSet(authentication.getAuthorities())).containsExactly("CUSTOM"); + verify(grantedAuthoritiesConverter).convert(any()); + } + + @Test + public void authenticateWhenValidateResponseAfterAssertionsThenCanHaveResponseAuthenticationConverterThatDoesntNeedANameID() { + Converter responseAuthenticationConverter = mock(Converter.class); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setValidateResponseAfterAssertions(true); + provider.setResponseAuthenticationConverter(responseAuthenticationConverter); + Response response = TestOpenSamlObjects + .signedResponseWithOneAssertion((r) -> r.getAssertions().get(0).setSubject(null)); + Saml2AuthenticationToken token = token(response, verifying(registration())); + provider.authenticate(token); + verify(responseAuthenticationConverter).convert(any()); + } + + @Test + public void authenticateWhenValidateResponseBeforeAssertionsThenMustHaveNameID() { + Converter responseAuthenticationConverter = mock(Converter.class); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setValidateResponseAfterAssertions(false); + provider.setResponseAuthenticationConverter(responseAuthenticationConverter); + Response response = TestOpenSamlObjects + .signedResponseWithOneAssertion((r) -> r.getAssertions().get(0).setSubject(null)); + Saml2AuthenticationToken token = token(response, verifying(registration())); + assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token)); + verifyNoInteractions(responseAuthenticationConverter); + } + @Test public void setResponseAuthenticationConverterWhenNullThenIllegalArgument() { // @formatter:off From eb83c35ded31b2ee9529f63883582c57cc395932 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:26:34 +0000 Subject: [PATCH 042/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.3 to 1.0.4 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e7f675c28..e9d5e60a84 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,7 +34,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.3" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.4" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 1e6fd62bedfbcb5e6da03dee23d07cab85fd6a80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:41:07 +0000 Subject: [PATCH 043/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.3 to 1.0.4 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a9ab595b6..4d2d6df31c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.3" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.4" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 923491628bc8890e36944b9f98aca315820dc865 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 03:40:33 +0000 Subject: [PATCH 044/504] Bump io.mockk:mockk from 1.13.17 to 1.14.0 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.17 to 1.14.0. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.13.17...1.14.0) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4d2d6df31c..fe846d7477 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.5" -io-mockk = "io.mockk:mockk:1.13.17" +io-mockk = "io.mockk:mockk:1.14.0" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From a10a35c2ac6204d1ea476eab03cd576c20b67330 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 04:01:52 +0000 Subject: [PATCH 045/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.3 to 1.0.4 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d4d15b58d7..36d2ec8f77 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.3" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.4" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 1ca33cae7011137d25adaee1038f7b3cc7f9cc27 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Thu, 10 Apr 2025 06:45:39 -0400 Subject: [PATCH 046/504] Make DPoP IatClaimValidator public to allow configuring clock and clockSkew Issue gh-16574 Closes gh-16921 --- .../jwt/DPoPProofJwtDecoderFactory.java | 35 +----- .../oauth2/jwt/JwtIssuedAtValidator.java | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+), 34 deletions(-) create mode 100644 oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtIssuedAtValidator.java diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java index 32a5913526..9b27313e37 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java @@ -19,7 +19,6 @@ package org.springframework.security.oauth2.jwt; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; -import java.time.Duration; import java.time.Instant; import java.util.Base64; import java.util.Collections; @@ -122,7 +121,7 @@ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory new DelegatingOAuth2TokenValidator<>( new JwtClaimValidator<>("htm", context.getMethod()::equals), new JwtClaimValidator<>("htu", context.getTargetUri()::equals), new JtiClaimValidator(), - new IatClaimValidator()); + new JwtIssuedAtValidator(true)); } private static final class JtiClaimValidator implements OAuth2TokenValidator { @@ -168,36 +167,4 @@ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory { - - private final Duration clockSkew = Duration.ofSeconds(60); - - private final Clock clock = Clock.systemUTC(); - - @Override - public OAuth2TokenValidatorResult validate(Jwt jwt) { - Assert.notNull(jwt, "DPoP proof jwt cannot be null"); - Instant issuedAt = jwt.getIssuedAt(); - if (issuedAt == null) { - OAuth2Error error = createOAuth2Error("iat claim is required."); - return OAuth2TokenValidatorResult.failure(error); - } - - // Check time window of validity - Instant now = Instant.now(this.clock); - Instant notBefore = now.minus(this.clockSkew); - Instant notAfter = now.plus(this.clockSkew); - if (issuedAt.isBefore(notBefore) || issuedAt.isAfter(notAfter)) { - OAuth2Error error = createOAuth2Error("iat claim is invalid."); - return OAuth2TokenValidatorResult.failure(error); - } - return OAuth2TokenValidatorResult.success(); - } - - private static OAuth2Error createOAuth2Error(String reason) { - return new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF, reason, null); - } - - } - } diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtIssuedAtValidator.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtIssuedAtValidator.java new file mode 100644 index 0000000000..2b7a5a8c58 --- /dev/null +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtIssuedAtValidator.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.jwt; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; + +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2TokenValidator; +import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; +import org.springframework.util.Assert; + +/** + * An {@link OAuth2TokenValidator} responsible for validating the {@link JwtClaimNames#IAT + * "iat"} claim in the {@link Jwt}. + * + * @author Joe Grandja + * @since 6.5 + * @see OAuth2TokenValidator + * @see Jwt + * @see JSON Web + * Token (JWT) + */ +public final class JwtIssuedAtValidator implements OAuth2TokenValidator { + + private final boolean required; + + private Duration clockSkew = Duration.ofSeconds(60); + + private Clock clock = Clock.systemUTC(); + + /** + * Constructs a {@code JwtIssuedAtValidator} with the defaults. + */ + public JwtIssuedAtValidator() { + this(false); + } + + /** + * Constructs a {@code JwtIssuedAtValidator} using the provided parameters. + * @param required {@code true} if the {@link JwtClaimNames#IAT "iat"} claim is + * REQUIRED in the {@link Jwt}, {@code false} otherwise + */ + public JwtIssuedAtValidator(boolean required) { + this.required = required; + } + + @Override + public OAuth2TokenValidatorResult validate(Jwt jwt) { + Assert.notNull(jwt, "jwt cannot be null"); + Instant issuedAt = jwt.getIssuedAt(); + if (issuedAt == null && this.required) { + OAuth2Error error = createOAuth2Error("iat claim is required."); + return OAuth2TokenValidatorResult.failure(error); + } + + if (issuedAt != null) { + // Check time window of validity + Instant now = Instant.now(this.clock); + Instant notBefore = now.minus(this.clockSkew); + Instant notAfter = now.plus(this.clockSkew); + if (issuedAt.isBefore(notBefore) || issuedAt.isAfter(notAfter)) { + OAuth2Error error = createOAuth2Error("iat claim is invalid."); + return OAuth2TokenValidatorResult.failure(error); + } + } + return OAuth2TokenValidatorResult.success(); + } + + /** + * Sets the clock skew. The default is 60 seconds. + * @param clockSkew the clock skew + */ + public void setClockSkew(Duration clockSkew) { + Assert.notNull(clockSkew, "clockSkew cannot be null"); + Assert.isTrue(clockSkew.getSeconds() >= 0, "clockSkew must be >= 0"); + this.clockSkew = clockSkew; + } + + /** + * Sets the {@link Clock} used in {@link Instant#now(Clock)}. + * @param clock the clock + */ + public void setClock(Clock clock) { + Assert.notNull(clock, "clock cannot be null"); + this.clock = clock; + } + + private static OAuth2Error createOAuth2Error(String reason) { + return new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, reason, null); + } + +} From 5841e35cae1910058e70c8ccb53219af73f5c0a9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 10 Apr 2025 08:37:00 -0600 Subject: [PATCH 047/504] Invert AuthorizeReturnObjectMethodInterceptor Dependency Closes gh-16922 --- .../AuthorizationProxyConfiguration.java | 15 +++++------ .../AuthorizationAdvisorProxyFactory.java | 16 +++++++----- ...uthorizeReturnObjectMethodInterceptor.java | 26 ++++++++++++++++++- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java index 6868703806..9ef918df58 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.security.config.annotation.method.configuration; import java.util.ArrayList; +import java.util.List; import org.aopalliance.intercept.MethodInterceptor; @@ -40,21 +41,19 @@ final class AuthorizationProxyConfiguration implements AopInfrastructureBean { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) static AuthorizationAdvisorProxyFactory authorizationProxyFactory( + ObjectProvider authorizationAdvisors, ObjectProvider> customizers) { - AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(new ArrayList<>()); + List advisors = new ArrayList<>(); + authorizationAdvisors.forEach(advisors::add); + AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(advisors); customizers.forEach((c) -> c.customize(factory)); return factory; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider provider, - AuthorizationAdvisorProxyFactory authorizationProxyFactory) { - provider.forEach(authorizationProxyFactory::addAdvisor); - AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor( - authorizationProxyFactory); - authorizationProxyFactory.addAdvisor(interceptor); - return interceptor; + static MethodInterceptor authorizeReturnObjectMethodInterceptor() { + return new AuthorizeReturnObjectMethodInterceptor(); } @Bean diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java index 3b18466743..dd4abb3754 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java @@ -100,16 +100,16 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx /** * Construct an {@link AuthorizationAdvisorProxyFactory} with the provided advisors. - * - *

- * The list may be empty, in the case where advisors are added later using - * {@link #addAdvisor}. * @param advisors the advisors to use * @since 6.4 */ public AuthorizationAdvisorProxyFactory(List advisors) { this.advisors = new ArrayList<>(advisors); - AnnotationAwareOrderComparator.sort(this.advisors); + for (AuthorizationAdvisor advisor : this.advisors) { + if (advisor instanceof AuthorizeReturnObjectMethodInterceptor interceptor) { + interceptor.setAuthorizationProxyFactory(this); + } + } } /** @@ -124,8 +124,8 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx advisors.add(AuthorizationManagerAfterMethodInterceptor.postAuthorize()); advisors.add(new PreFilterAuthorizationMethodInterceptor()); advisors.add(new PostFilterAuthorizationMethodInterceptor()); + advisors.add(new AuthorizeReturnObjectMethodInterceptor()); AuthorizationAdvisorProxyFactory proxyFactory = new AuthorizationAdvisorProxyFactory(advisors); - proxyFactory.addAdvisor(new AuthorizeReturnObjectMethodInterceptor(proxyFactory)); AnnotationAwareOrderComparator.sort(proxyFactory.advisors); return proxyFactory; } @@ -142,8 +142,8 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx advisors.add(AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize()); advisors.add(new PreFilterAuthorizationReactiveMethodInterceptor()); advisors.add(new PostFilterAuthorizationReactiveMethodInterceptor()); + advisors.add(new AuthorizeReturnObjectMethodInterceptor()); AuthorizationAdvisorProxyFactory proxyFactory = new AuthorizationAdvisorProxyFactory(advisors); - proxyFactory.addAdvisor(new AuthorizeReturnObjectMethodInterceptor(proxyFactory)); AnnotationAwareOrderComparator.sort(proxyFactory.advisors); return proxyFactory; } @@ -230,7 +230,9 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx * them. * @param advisor * @since 6.4 + * @deprecated please provide all advisors in the constructor */ + @Deprecated public void addAdvisor(AuthorizationAdvisor advisor) { this.advisors.add(advisor); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizeReturnObjectMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizeReturnObjectMethodInterceptor.java index 5308b8d251..5a69fa11f1 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizeReturnObjectMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizeReturnObjectMethodInterceptor.java @@ -39,7 +39,7 @@ import org.springframework.util.ClassUtils; */ public final class AuthorizeReturnObjectMethodInterceptor implements AuthorizationAdvisor { - private final AuthorizationProxyFactory authorizationProxyFactory; + private AuthorizationProxyFactory authorizationProxyFactory; private Pointcut pointcut = Pointcuts.intersection( new MethodReturnTypePointcut(Predicate.not(ClassUtils::isVoidType)), @@ -47,6 +47,19 @@ public final class AuthorizeReturnObjectMethodInterceptor implements Authorizati private int order = AuthorizationInterceptorsOrder.SECURE_RESULT.getOrder(); + /** + * Construct the interceptor + * + *

+ * Using this constructor requires you to specify + * {@link #setAuthorizationProxyFactory} + *

+ * @since 6.5 + */ + public AuthorizeReturnObjectMethodInterceptor() { + + } + public AuthorizeReturnObjectMethodInterceptor(AuthorizationProxyFactory authorizationProxyFactory) { Assert.notNull(authorizationProxyFactory, "authorizationProxyFactory cannot be null"); this.authorizationProxyFactory = authorizationProxyFactory; @@ -58,9 +71,20 @@ public final class AuthorizeReturnObjectMethodInterceptor implements Authorizati if (result == null) { return null; } + Assert.notNull(this.authorizationProxyFactory, "authorizationProxyFactory cannot be null"); return this.authorizationProxyFactory.proxy(result); } + /** + * Use this {@link AuthorizationProxyFactory} + * @param authorizationProxyFactory the proxy factory to use + * @since 6.5 + */ + public void setAuthorizationProxyFactory(AuthorizationProxyFactory authorizationProxyFactory) { + Assert.notNull(authorizationProxyFactory, "authorizationProxyFactory cannot be null"); + this.authorizationProxyFactory = authorizationProxyFactory; + } + @Override public int getOrder() { return this.order; From 6438603cb6485ed846497d5f5d51be03e2e49d5b Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 10 Apr 2025 10:41:36 -0600 Subject: [PATCH 048/504] Pick Up TargetVisitor Beans Closes gh-16923 --- .../AuthorizationProxyConfiguration.java | 7 ++++++- .../servlet/authorization/method-security.adoc | 16 +++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java index 9ef918df58..a723a9a13f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.security.aot.hint.SecurityHintsRegistrar; import org.springframework.security.authorization.AuthorizationProxyFactory; import org.springframework.security.authorization.method.AuthorizationAdvisor; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor; import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor; import org.springframework.security.config.Customizer; @@ -41,11 +42,15 @@ final class AuthorizationProxyConfiguration implements AopInfrastructureBean { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) static AuthorizationAdvisorProxyFactory authorizationProxyFactory( - ObjectProvider authorizationAdvisors, + ObjectProvider authorizationAdvisors, ObjectProvider targetVisitors, ObjectProvider> customizers) { List advisors = new ArrayList<>(); authorizationAdvisors.forEach(advisors::add); + List visitors = new ArrayList<>(); + targetVisitors.orderedStream().forEach(visitors::add); + visitors.add(TargetVisitor.defaults()); AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory(advisors); + factory.setTargetVisitor(TargetVisitor.of(visitors.toArray(TargetVisitor[]::new))); customizers.forEach((c) -> c.customize(factory)); return factory; } diff --git a/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc b/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc index c3bfab7db7..944e1813f2 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc @@ -2143,9 +2143,13 @@ Java:: + [source,java,role="primary"] ---- +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor; + +// ... + @Bean -static Customizer skipValueTypes() { - return (factory) -> factory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); +static TargetVisitor skipValueTypes() { + return TargetVisitor.defaultsSkipValueTypes(); } ---- @@ -2153,10 +2157,12 @@ Kotlin:: + [source,kotlin,role="secondary"] ---- +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor + +// ... + @Bean -open fun skipValueTypes() = Customizer { - it.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()) -} +open fun skipValueTypes() = TargetVisitor.defaultsSkipValueTypes() ---- ====== From 09ba5397fb1ddb9e07cca8741a586b4094277230 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 10 Apr 2025 10:42:08 -0600 Subject: [PATCH 049/504] Add Support for Authorizing Spring MVC Return Types Closes gh-16059 --- .../AuthorizationProxyWebConfiguration.java | 65 +++++++++++++++++ .../configuration/MethodSecuritySelector.java | 8 ++- .../ReactiveMethodSecuritySelector.java | 8 ++- ...ePostMethodSecurityConfigurationTests.java | 67 +++++++++++++++++- ...ctiveMethodSecurityConfigurationTests.java | 69 +++++++++++++++++-- 5 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java new file mode 100644 index 0000000000..4af062ef96 --- /dev/null +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.config.annotation.method.configuration; + +import java.util.Map; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Role; +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.View; + +@Configuration +class AuthorizationProxyWebConfiguration { + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + AuthorizationAdvisorProxyFactory.TargetVisitor webTargetVisitor() { + return new WebTargetVisitor(); + } + + static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor { + + @Override + public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { + if (target instanceof ResponseEntity entity) { + return new ResponseEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders(), + entity.getStatusCode()); + } + if (target instanceof HttpEntity entity) { + return new HttpEntity<>(proxyFactory.proxy(entity.getBody()), entity.getHeaders()); + } + if (target instanceof ModelAndView mav) { + View view = mav.getView(); + String viewName = mav.getViewName(); + Map model = (Map) proxyFactory.proxy(mav.getModel()); + ModelAndView proxied = (view != null) ? new ModelAndView(view, model) + : new ModelAndView(viewName, model); + proxied.setStatus(mav.getStatus()); + return proxied; + } + return null; + } + + } + +} diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecuritySelector.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecuritySelector.java index 47d5d23f76..ed2c7cb03e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecuritySelector.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecuritySelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,9 @@ final class MethodSecuritySelector implements ImportSelector { private static final boolean isDataPresent = ClassUtils .isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null); + private static final boolean isWebPresent = ClassUtils + .isPresent("org.springframework.web.servlet.DispatcherServlet", null); + private static final boolean isObservabilityPresent = ClassUtils .isPresent("io.micrometer.observation.ObservationRegistry", null); @@ -67,6 +70,9 @@ final class MethodSecuritySelector implements ImportSelector { if (isDataPresent) { imports.add(AuthorizationProxyDataConfiguration.class.getName()); } + if (isWebPresent) { + imports.add(AuthorizationProxyWebConfiguration.class.getName()); + } if (isObservabilityPresent) { imports.add(MethodObservationConfiguration.class.getName()); } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java index c204b33aaa..8bf18bf3eb 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,9 @@ class ReactiveMethodSecuritySelector implements ImportSelector { private static final boolean isDataPresent = ClassUtils .isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null); + private static final boolean isWebPresent = ClassUtils.isPresent("org.springframework.web.server.ServerWebExchange", + null); + private static final boolean isObservabilityPresent = ClassUtils .isPresent("io.micrometer.observation.ObservationRegistry", null); @@ -61,6 +64,9 @@ class ReactiveMethodSecuritySelector implements ImportSelector { if (isDataPresent) { imports.add(AuthorizationProxyDataConfiguration.class.getName()); } + if (isWebPresent) { + imports.add(AuthorizationProxyWebConfiguration.class.getName()); + } if (isObservabilityPresent) { imports.add(ReactiveMethodObservationConfiguration.class.getName()); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index d07e4484a7..297564fa0d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -60,6 +60,8 @@ import org.springframework.context.annotation.Role; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationConfigurationException; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.annotation.BusinessService; @@ -90,7 +92,6 @@ import org.springframework.security.authorization.method.AuthorizeReturnObject; import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler; import org.springframework.security.authorization.method.MethodInvocationResult; import org.springframework.security.authorization.method.PrePostTemplateDefaults; -import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.core.GrantedAuthorityDefaults; import org.springframework.security.config.observation.SecurityObservationSettings; @@ -109,6 +110,7 @@ import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.ModelAndView; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -729,6 +731,49 @@ public class PrePostMethodSecurityConfigurationTests { assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude); } + @Test + @WithMockUser(authorities = "airplane:read") + public void findByIdWhenAuthorizedResponseEntityThenAuthorizes() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = flights.webFindById("1").getBody(); + assertThatNoException().isThrownBy(flight::getAltitude); + assertThatNoException().isThrownBy(flight::getSeats); + assertThat(flights.webFindById("5").getBody()).isNull(); + } + + @Test + @WithMockUser(authorities = "seating:read") + public void findByIdWhenUnauthorizedResponseEntityThenDenies() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = flights.webFindById("1").getBody(); + assertThatNoException().isThrownBy(flight::getSeats); + assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude); + } + + @Test + @WithMockUser(authorities = "airplane:read") + public void findByIdWhenAuthorizedModelAndViewThenAuthorizes() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = (Flight) flights.webViewFindById("1").getModel().get("flight"); + assertThatNoException().isThrownBy(flight::getAltitude); + assertThatNoException().isThrownBy(flight::getSeats); + assertThat(flights.webViewFindById("5").getModel().get("flight")).isNull(); + } + + @Test + @WithMockUser(authorities = "seating:read") + public void findByIdWhenUnauthorizedModelAndViewThenDenies() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = (Flight) flights.webViewFindById("1").getModel().get("flight"); + assertThatNoException().isThrownBy(flight::getSeats); + assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude); + assertThat(flights.webViewFindById("5").getModel().get("flight")).isNull(); + } + @Test @WithMockUser(authorities = "seating:read") public void findAllWhenUnauthorizedResultThenDenies() { @@ -1601,8 +1646,8 @@ public class PrePostMethodSecurityConfigurationTests { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static Customizer skipValueTypes() { - return (f) -> f.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); + static TargetVisitor skipValueTypes() { + return TargetVisitor.defaultsSkipValueTypes(); } @Bean @@ -1646,6 +1691,22 @@ public class PrePostMethodSecurityConfigurationTests { this.flights.remove(id); } + ResponseEntity webFindById(String id) { + Flight flight = this.flights.get(id); + if (flight == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(flight); + } + + ModelAndView webViewFindById(String id) { + Flight flight = this.flights.get(id); + if (flight == null) { + return new ModelAndView("error", HttpStatusCode.valueOf(404)); + } + return new ModelAndView("flights", Map.of("flight", flight)); + } + } @AuthorizeReturnObject diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostReactiveMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostReactiveMethodSecurityConfigurationTests.java index b82eb985bc..32e08c166a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostReactiveMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostReactiveMethodSecurityConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,8 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProce import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.annotation.Secured; @@ -54,9 +56,9 @@ import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.authorization.AuthorizationDeniedException; import org.springframework.security.authorization.method.AuthorizationAdvisor; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor; import org.springframework.security.authorization.method.AuthorizeReturnObject; import org.springframework.security.authorization.method.PrePostTemplateDefaults; -import org.springframework.security.config.Customizer; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.core.Authentication; @@ -65,6 +67,7 @@ import org.springframework.security.test.context.annotation.SecurityTestExecutio import org.springframework.security.test.context.support.WithMockUser; import org.springframework.stereotype.Component; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.servlet.ModelAndView; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -361,6 +364,48 @@ public class PrePostReactiveMethodSecurityConfigurationTests { assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> flight.getAltitude().block()); } + @Test + @WithMockUser(authorities = "airplane:read") + public void findByIdWhenAuthorizedResponseEntityThenAuthorizes() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = flights.webFindById("1").block().getBody(); + assertThatNoException().isThrownBy(() -> flight.getAltitude().block()); + assertThatNoException().isThrownBy(() -> flight.getSeats().block()); + } + + @Test + @WithMockUser(authorities = "seating:read") + public void findByIdWhenUnauthorizedResponseEntityThenDenies() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = flights.webFindById("1").block().getBody(); + assertThatNoException().isThrownBy(() -> flight.getSeats().block()); + assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> flight.getAltitude().block()); + } + + @Test + @WithMockUser(authorities = "airplane:read") + public void findByIdWhenAuthorizedModelAndViewThenAuthorizes() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = (Flight) flights.webViewFindById("1").block().getModel().get("flight"); + assertThatNoException().isThrownBy(() -> flight.getAltitude().block()); + assertThatNoException().isThrownBy(() -> flight.getSeats().block()); + assertThat(flights.webViewFindById("5").block().getModel().get("flight")).isNull(); + } + + @Test + @WithMockUser(authorities = "seating:read") + public void findByIdWhenUnauthorizedModelAndViewThenDenies() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + Flight flight = (Flight) flights.webViewFindById("1").block().getModel().get("flight"); + assertThatNoException().isThrownBy(() -> flight.getSeats().block()); + assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> flight.getAltitude().block()); + assertThat(flights.webViewFindById("5").block().getModel().get("flight")).isNull(); + } + @Test @WithMockUser(authorities = "seating:read") public void findAllWhenUnauthorizedResultThenDenies() { @@ -659,8 +704,8 @@ public class PrePostReactiveMethodSecurityConfigurationTests { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static Customizer skipValueTypes() { - return (f) -> f.setTargetVisitor(AuthorizationAdvisorProxyFactory.TargetVisitor.defaultsSkipValueTypes()); + static TargetVisitor skipValueTypes() { + return TargetVisitor.defaultsSkipValueTypes(); } @Bean @@ -724,6 +769,22 @@ public class PrePostReactiveMethodSecurityConfigurationTests { return Mono.empty(); } + Mono> webFindById(String id) { + Flight flight = this.flights.get(id); + if (flight == null) { + return Mono.just(ResponseEntity.notFound().build()); + } + return Mono.just(ResponseEntity.ok(flight)); + } + + Mono webViewFindById(String id) { + Flight flight = this.flights.get(id); + if (flight == null) { + return Mono.just(new ModelAndView("error", HttpStatusCode.valueOf(404))); + } + return Mono.just(new ModelAndView("flights", Map.of("flight", flight))); + } + } @AuthorizeReturnObject From 0e7048272568309b9578a7c01d3d97b5433c1dea Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 10 Apr 2025 15:55:00 -0600 Subject: [PATCH 050/504] Fix Formatting --- .../PrePostMethodSecurityConfigurationTests.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index 297564fa0d..8eec0f1bce 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -39,6 +39,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mockito; import org.springframework.aop.Advisor; import org.springframework.aop.config.AopConfigUtils; @@ -60,6 +61,7 @@ import org.springframework.context.annotation.Role; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationConfigurationException; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; @@ -1646,6 +1648,14 @@ public class PrePostMethodSecurityConfigurationTests { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + @Order(1) + static TargetVisitor mock() { + return Mockito.mock(TargetVisitor.class); + } + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + @Order(0) static TargetVisitor skipValueTypes() { return TargetVisitor.defaultsSkipValueTypes(); } From 15c2b156f19826bcebf4cc8af9e2511d84bb8673 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:10:05 -0500 Subject: [PATCH 051/504] Update Client Authentication examples Closes gh-16925 987d9c9788ba0343f543083c87613fb5 --- .../oauth2/client/client-authentication.adoc | 57 ++++++------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc index 62197146c2..8a3a440366 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc @@ -27,7 +27,7 @@ spring: ... ---- -The following example shows how to configure `DefaultAuthorizationCodeTokenResponseClient` to disable URL encoding of the client credentials: +The following example shows how to configure `RestClientAuthorizationCodeTokenResponseClient` to disable URL encoding of the client credentials: [tabs] ====== @@ -39,13 +39,9 @@ DefaultOAuth2TokenRequestHeadersConverter h new DefaultOAuth2TokenRequestHeadersConverter<>(); headersConverter.setEncodeClientCredentials(false); -OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter = - new OAuth2AuthorizationCodeGrantRequestEntityConverter(); -requestEntityConverter.setHeadersConverter(headersConverter); - -DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = - new DefaultAuthorizationCodeTokenResponseClient(); -tokenResponseClient.setRequestEntityConverter(requestEntityConverter); +RestClientAuthorizationCodeTokenResponseClient tokenResponseClient = + new RestClientAuthorizationCodeTokenResponseClient(); +tokenResponseClient.setHeadersConverter(headersConverter); ---- Kotlin:: @@ -55,11 +51,8 @@ Kotlin:: val headersConverter = DefaultOAuth2TokenRequestHeadersConverter() headersConverter.setEncodeClientCredentials(false) -val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter() -requestEntityConverter.setHeadersConverter(headersConverter) - -val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient() -tokenResponseClient.setRequestEntityConverter(requestEntityConverter) +val tokenResponseClient = RestClientAuthorizationCodeTokenResponseClient() +tokenResponseClient.setHeadersConverter(headersConverter) ---- ====== @@ -119,7 +112,7 @@ spring: ... ---- -The following example shows how to configure `DefaultAuthorizationCodeTokenResponseClient`: +The following example shows how to configure `RestClientAuthorizationCodeTokenResponseClient`: [tabs] ====== @@ -140,14 +133,10 @@ Function jwkResolver = (clientRegistration) -> { return null; }; -OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter = - new OAuth2AuthorizationCodeGrantRequestEntityConverter(); -requestEntityConverter.addParametersConverter( +RestClientAuthorizationCodeTokenResponseClient tokenResponseClient = + new RestClientAuthorizationCodeTokenResponseClient(); +tokenResponseClient.addParametersConverter( new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver)); - -DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = - new DefaultAuthorizationCodeTokenResponseClient(); -tokenResponseClient.setRequestEntityConverter(requestEntityConverter); ---- Kotlin:: @@ -168,13 +157,10 @@ val jwkResolver: Function = null } -val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter() -requestEntityConverter.addParametersConverter( +val tokenResponseClient = RestClientAuthorizationCodeTokenResponseClient() +tokenResponseClient.addParametersConverter( NimbusJwtClientAuthenticationParametersConverter(jwkResolver) ) - -val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient() -tokenResponseClient.setRequestEntityConverter(requestEntityConverter) ---- ====== @@ -198,7 +184,7 @@ spring: ... ---- -The following example shows how to configure `DefaultClientCredentialsTokenResponseClient`: +The following example shows how to configure `RestClientClientCredentialsTokenResponseClient`: [tabs] ====== @@ -218,14 +204,10 @@ Function jwkResolver = (clientRegistration) -> { return null; }; -OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter = - new OAuth2ClientCredentialsGrantRequestEntityConverter(); -requestEntityConverter.addParametersConverter( +RestClientClientCredentialsTokenResponseClient tokenResponseClient = + new RestClientClientCredentialsTokenResponseClient(); +tokenResponseClient.addParametersConverter( new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver)); - -DefaultClientCredentialsTokenResponseClient tokenResponseClient = - new DefaultClientCredentialsTokenResponseClient(); -tokenResponseClient.setRequestEntityConverter(requestEntityConverter); ---- Kotlin:: @@ -245,13 +227,10 @@ val jwkResolver = Function { clientRegistration: Clien null } -val requestEntityConverter = OAuth2ClientCredentialsGrantRequestEntityConverter() -requestEntityConverter.addParametersConverter( +val tokenResponseClient = RestClientClientCredentialsTokenResponseClient() +tokenResponseClient.addParametersConverter( NimbusJwtClientAuthenticationParametersConverter(jwkResolver) ) - -val tokenResponseClient = DefaultClientCredentialsTokenResponseClient() -tokenResponseClient.setRequestEntityConverter(requestEntityConverter) ---- ====== From 0d3d6f75f8adac583bafc926bd6e37bd12fbeb3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:14:15 +0000 Subject: [PATCH 052/504] Bump org-aspectj from 1.9.22.1 to 1.9.24 Bumps `org-aspectj` from 1.9.22.1 to 1.9.24. Updates `org.aspectj:aspectjrt` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) Updates `org.aspectj:aspectjweaver` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) --- updated-dependencies: - dependency-name: org.aspectj:aspectjrt dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.aspectj:aspectjweaver dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e9d5e60a84..9d52e7c45f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" org-apache-maven-resolver = "1.9.22" -org-aspectj = "1.9.22.1" +org-aspectj = "1.9.24" org-bouncycastle = "1.78.1" org-eclipse-jetty = "11.0.25" org-jetbrains-kotlin = "1.9.25" From 2ce4aecec7ff851325708aafca1c7f5e4476bbd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:18:05 +0000 Subject: [PATCH 053/504] Bump org-aspectj from 1.9.22.1 to 1.9.24 Bumps `org-aspectj` from 1.9.22.1 to 1.9.24. Updates `org.aspectj:aspectjrt` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) Updates `org.aspectj:aspectjweaver` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) --- updated-dependencies: - dependency-name: org.aspectj:aspectjrt dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.aspectj:aspectjweaver dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 36d2ec8f77..f8a9091f8a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" org-apache-maven-resolver = "1.9.22" -org-aspectj = "1.9.22.1" +org-aspectj = "1.9.24" org-bouncycastle = "1.79" org-eclipse-jetty = "11.0.25" org-jetbrains-kotlin = "1.9.25" From ce1532703a499549d93b96e5e7a0e11f6f3c1db7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:30:41 +0000 Subject: [PATCH 054/504] Bump com.google.code.gson:gson from 2.12.1 to 2.13.0 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.12.1 to 2.13.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.12.1...gson-parent-2.13.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe846d7477..a4f74f5a8c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -94,7 +94,7 @@ org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-lda org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" -com-google-code-gson-gson = "com.google.code.gson:gson:2.12.1" +com-google-code-gson-gson = "com.google.code.gson:gson:2.13.0" com-thaiopensource-trag = "com.thaiopensource:trang:20091111" net-sourceforge-saxon-saxon = "net.sourceforge.saxon:saxon:9.1.0.8" org-yaml-snakeyaml = "org.yaml:snakeyaml:1.33" From cfe2a9c39fb0b8464fb2ab2088bed6da7f0f2753 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:31:00 +0000 Subject: [PATCH 055/504] Bump io.micrometer:context-propagation from 1.1.2 to 1.1.3 Bumps [io.micrometer:context-propagation](https://github.com/micrometer-metrics/context-propagation) from 1.1.2 to 1.1.3. - [Release notes](https://github.com/micrometer-metrics/context-propagation/releases) - [Commits](https://github.com/micrometer-metrics/context-propagation/compare/v1.1.2...v1.1.3) --- updated-dependencies: - dependency-name: io.micrometer:context-propagation dependency-version: 1.1.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a4f74f5a8c..3733694b89 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version. com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" -io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.2" +io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.5" io-mockk = "io.mockk:mockk:1.14.0" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" From cbfb1e002f7192be12ee81cc9c3a300e77b6992c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:30:52 +0000 Subject: [PATCH 056/504] Bump org-aspectj from 1.9.22.1 to 1.9.24 Bumps `org-aspectj` from 1.9.22.1 to 1.9.24. Updates `org.aspectj:aspectjrt` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) Updates `org.aspectj:aspectjweaver` from 1.9.22.1 to 1.9.24 - [Release notes](https://github.com/eclipse/org.aspectj/releases) - [Commits](https://github.com/eclipse/org.aspectj/commits) --- updated-dependencies: - dependency-name: org.aspectj:aspectjrt dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.aspectj:aspectjweaver dependency-version: 1.9.24 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3733694b89..eafeee9139 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" org-apache-maven-resolver = "1.9.22" -org-aspectj = "1.9.22.1" +org-aspectj = "1.9.24" org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" org-jetbrains-kotlin = "1.9.25" From fdff4eca1ae867e85ba65cea0fbe5432fbb99768 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:30:34 +0000 Subject: [PATCH 057/504] Bump org.junit:junit-bom from 5.12.1 to 5.12.2 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.12.1 to 5.12.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.12.1...r5.12.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 5.12.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eafeee9139..f30449a8ea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -76,7 +76,7 @@ org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" org-jetbrains-kotlinx-kotlinx-coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "org-jetbrains-kotlinx" } -org-junit-junit-bom = "org.junit:junit-bom:5.12.1" +org-junit-junit-bom = "org.junit:junit-bom:5.12.2" org-mockito-mockito-bom = { module = "org.mockito:mockito-bom", version.ref = "org-mockito" } org-opensaml-opensaml-saml-api = { module = "org.opensaml:opensaml-saml-api", version.ref = "org-opensaml" } org-opensaml-opensaml-saml-impl = { module = "org.opensaml:opensaml-saml-impl", version.ref = "org-opensaml" } From a5fa197105d3bd421b8f77cc6eaa88407b78bd39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 03:43:22 +0000 Subject: [PATCH 058/504] Bump io.micrometer:micrometer-observation from 1.14.5 to 1.14.6 Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.5 to 1.14.6. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.5...v1.14.6) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-observation dependency-version: 1.14.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f30449a8ea..2caa04a4b4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" -io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.5" +io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" io-mockk = "io.mockk:mockk:1.14.0" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } From ae82be70c3c880e17b6c339393b783af7aa52986 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:06:05 -0600 Subject: [PATCH 059/504] Add Needed Runtime Hints Issue gh-16536 --- .../WebSecurityConfigurationRuntimeHints.java | 2 +- .../resources/META-INF/spring/aot.factories | 3 +- ...ecurityConfigurationRuntimeHintsTests.java | 56 +++++++++++++++++++ .../aot/hint/WebTestUtilsRuntimeHints.java | 4 ++ .../hint/WebTestUtilsRuntimeHintsTests.java | 4 ++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java diff --git a/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java index bf1b184179..5f3e62aaa1 100644 --- a/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java +++ b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java @@ -23,7 +23,7 @@ import org.springframework.aot.hint.TypeReference; /** * Runtime hints for - * {@link org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration} + * {@link org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration} * * @author Marcus da Coregio */ diff --git a/config/src/main/resources/META-INF/spring/aot.factories b/config/src/main/resources/META-INF/spring/aot.factories index a8b18bef35..1d9bf65597 100644 --- a/config/src/main/resources/META-INF/spring/aot.factories +++ b/config/src/main/resources/META-INF/spring/aot.factories @@ -3,4 +3,5 @@ org.springframework.security.config.annotation.authentication.configuration.Auth org.springframework.aot.hint.RuntimeHintsRegistrar=\ org.springframework.security.config.aot.hint.OAuth2LoginRuntimeHints,\ -org.springframework.security.config.aot.hint.WebMvcSecurityConfigurationRuntimeHints +org.springframework.security.config.aot.hint.WebMvcSecurityConfigurationRuntimeHints, \ +org.springframework.security.config.aot.hint.WebSecurityConfigurationRuntimeHints diff --git a/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java b/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java new file mode 100644 index 0000000000..7e94b044b9 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.config.aot.hint; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.core.io.support.SpringFactoriesLoader; +import org.springframework.util.ClassUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebSecurityConfigurationRuntimeHints} + * + * @author Marcus da Coregio + */ +class WebSecurityConfigurationRuntimeHintsTests { + + private final RuntimeHints hints = new RuntimeHints(); + + @BeforeEach + void setup() { + SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories") + .load(RuntimeHintsRegistrar.class) + .forEach((registrar) -> registrar.registerHints(this.hints, ClassUtils.getDefaultClassLoader())); + } + + @Test + void compositeFilterChainProxyHasHints() { + assertThat(RuntimeHintsPredicates.reflection() + .onType(TypeReference + .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy")) + .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.hints); + } + +} diff --git a/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java b/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java index 6ca4fd51bd..9b098dd863 100644 --- a/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java +++ b/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java @@ -51,6 +51,10 @@ class WebTestUtilsRuntimeHints implements RuntimeHintsRegistrar { .registerType(TypeReference .of("org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy"), MemberCategory.INVOKE_DECLARED_METHODS); + hints.reflection() + .registerType(TypeReference + .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy"), + MemberCategory.INVOKE_DECLARED_METHODS); } private void registerCsrfTokenRepositoryHints(RuntimeHints hints) { diff --git a/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java b/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java index 128de6681f..6fb662dca3 100644 --- a/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java +++ b/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java @@ -62,6 +62,10 @@ class WebTestUtilsRuntimeHintsTests { .onType(TypeReference .of("org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy")) .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints); + assertThat(RuntimeHintsPredicates.reflection() + .onType(TypeReference + .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy")) + .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints); } @Test From 178ca736739a705da74e28d4f9227755e872f237 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 14 Apr 2025 13:42:44 -0600 Subject: [PATCH 060/504] Fix Type Check Issue gh-16536 --- .../WebSecurityConfiguration.java | 10 +++----- .../configuration/EnableWebSecurityTests.java | 24 ++++++++++++++++--- .../web/configurers/NamespaceDebugTests.java | 1 - 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java index d1f6ae8699..abc753d3bc 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java @@ -229,7 +229,7 @@ public class WebSecurityConfiguration implements ImportAware { BeanDefinition filterChainProxy = registry .getBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); - if (filterChainProxy.getResolvableType().isAssignableFrom(CompositeFilterChainProxy.class)) { + if (filterChainProxy.getResolvableType().isInstance(CompositeFilterChainProxy.class)) { return; } @@ -244,11 +244,6 @@ public class WebSecurityConfiguration implements ImportAware { .rootBeanDefinition(CompositeFilterChainProxy.class) .addConstructorArgValue(filters); - if (filterChainProxy.getResolvableType().isInstance(DebugFilter.class)) { - compositeSpringSecurityFilterChainBldr = BeanDefinitionBuilder.rootBeanDefinition(DebugFilter.class) - .addConstructorArgValue(compositeSpringSecurityFilterChainBldr.getBeanDefinition()); - } - registry.removeBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); registry.registerBeanDefinition(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, compositeSpringSecurityFilterChainBldr.getBeanDefinition()); @@ -308,6 +303,7 @@ public class WebSecurityConfiguration implements ImportAware { * @param filters the Filters to delegate to. One of which must be * FilterChainProxy. */ + @Autowired CompositeFilterChainProxy(List filters) { this.doFilterDelegate = createDoFilterDelegate(filters); this.springSecurityFilterChain = findFilterChainProxy(filters); @@ -403,7 +399,7 @@ public class WebSecurityConfiguration implements ImportAware { return fcp; } if (filter instanceof DebugFilter debugFilter) { - return new CompositeFilterChainProxy(debugFilter, debugFilter.getFilterChainProxy()); + return debugFilter.getFilterChainProxy(); } } throw new IllegalStateException("Couldn't find FilterChainProxy in " + filters); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java index 19bd2c8fa4..1a2734775f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurityTests.java @@ -16,8 +16,13 @@ package org.springframework.security.config.annotation.web.configuration; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -28,7 +33,6 @@ import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.debug.DebugFilter; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -36,6 +40,10 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -52,9 +60,19 @@ public class EnableWebSecurityTests { private MockMvc mockMvc; @Test - public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() { + public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() throws Exception { + Appender appender = mockAppenderFor("Spring Security Debugger"); this.spring.register(ChildSecurityConfig.class).autowire(); - this.spring.getContext().getBean("springSecurityFilterChain", DebugFilter.class); + this.mockMvc.perform(get("/")); + verify(appender, atLeastOnce()).doAppend(any(ILoggingEvent.class)); + } + + private Appender mockAppenderFor(String name) { + Appender appender = mock(Appender.class); + Logger logger = (Logger) LoggerFactory.getLogger(name); + logger.setLevel(Level.DEBUG); + logger.addAppender(appender); + return appender; } // gh-14370 diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java index 86c2cd2356..4da63d4485 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceDebugTests.java @@ -59,7 +59,6 @@ public class NamespaceDebugTests { Appender appender = mockAppenderFor("Spring Security Debugger"); this.spring.register(DebugWebSecurity.class).autowire(); this.mvc.perform(get("/")); - assertThat(filterChainClass()).isEqualTo(DebugFilter.class); verify(appender, atLeastOnce()).doAppend(any(ILoggingEvent.class)); } From 791feee35584729f45dcb22ed4766aa4ab4de245 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Mon, 14 Apr 2025 07:38:08 -0400 Subject: [PATCH 061/504] Prevent downgraded usage of DPoP-bound access tokens Issue gh-16574 Closes gh-16937 --- .../BearerTokenAuthenticationFilter.java | 28 ++++++++++++++++++- .../BearerTokenAuthenticationFilterTests.java | 26 ++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java index 5ffd2ed888..9cad61d0cb 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.resource.web.authentication; import java.io.IOException; +import java.util.Map; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -32,7 +33,11 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; +import org.springframework.security.oauth2.core.ClaimAccessor; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.server.resource.BearerTokenError; +import org.springframework.security.oauth2.server.resource.BearerTokenErrors; +import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; @@ -45,6 +50,8 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; /** @@ -135,6 +142,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { try { AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request); Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest); + if (isDPoPBoundAccessToken(authenticationResult)) { + // Prevent downgraded usage of DPoP-bound access tokens, + // by rejecting a DPoP-bound access token received as a bearer token. + BearerTokenError error = BearerTokenErrors.invalidToken("Invalid bearer token"); + throw new OAuth2AuthenticationException(error); + } SecurityContext context = this.securityContextHolderStrategy.createEmptyContext(); context.setAuthentication(authenticationResult); this.securityContextHolderStrategy.setContext(context); @@ -217,4 +230,17 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { this.authenticationDetailsSource = authenticationDetailsSource; } + private static boolean isDPoPBoundAccessToken(Authentication authentication) { + if (!(authentication instanceof AbstractOAuth2TokenAuthenticationToken accessTokenAuthentication)) { + return false; + } + ClaimAccessor accessTokenClaims = accessTokenAuthentication::getTokenAttributes; + String jwkThumbprintClaim = null; + Map confirmationMethodClaim = accessTokenClaims.getClaimAsMap("cnf"); + if (!CollectionUtils.isEmpty(confirmationMethodClaim) && confirmationMethodClaim.containsKey("jkt")) { + jwkThumbprintClaim = (String) confirmationMethodClaim.get("jkt"); + } + return StringUtils.hasText(jwkThumbprintClaim); + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index 63d306f13e..cc7477684f 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.resource.web.authentication; import java.io.IOException; +import java.util.Collections; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -41,10 +42,14 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.BearerTokenError; import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationFailureHandler; @@ -239,6 +244,25 @@ public class BearerTokenAuthenticationFilterTests { verify(strategy).setContext(any()); } + @Test + public void doFilterWhenDPoPBoundTokenDowngradedThenPropagatesError() throws ServletException, IOException { + Jwt jwt = TestJwts.jwt().claim("cnf", Collections.singletonMap("jkt", "jwk-thumbprint")).build(); + JwtAuthenticationToken authenticationResult = new JwtAuthenticationToken(jwt); + given(this.bearerTokenResolver.resolve(this.request)).willReturn("token"); + given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))) + .willReturn(authenticationResult); + BearerTokenAuthenticationFilter filter = addMocks( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.setAuthenticationFailureHandler(this.authenticationFailureHandler); + filter.doFilter(this.request, this.response, this.filterChain); + ArgumentCaptor exceptionCaptor = ArgumentCaptor + .forClass(OAuth2AuthenticationException.class); + verify(this.authenticationFailureHandler).onAuthenticationFailure(any(), any(), exceptionCaptor.capture()); + OAuth2Error error = exceptionCaptor.getValue().getError(); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN); + assertThat(error.getDescription()).isEqualTo("Invalid bearer token"); + } + @Test public void setAuthenticationEntryPointWhenNullThenThrowsException() { BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager); From f86c4ad38326340526660b7aeb7a30277cd32e86 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 14 Apr 2025 13:58:04 -0600 Subject: [PATCH 062/504] Polish Native Support - Remove unneeded deprecateion marker - Add missing reflected class Issue gh-16536 --- .../web/configuration/WebMvcSecurityConfiguration.java | 1 - .../web/configuration/WebSecurityConfiguration.java | 6 ------ .../aot/hint/WebSecurityConfigurationRuntimeHints.java | 3 +++ .../aot/hint/WebSecurityConfigurationRuntimeHintsTests.java | 3 +++ 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java index 85dd907ff8..73a56456d8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java @@ -122,7 +122,6 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex } @Bean - @Deprecated static BeanDefinitionRegistryPostProcessor springSecurityHandlerMappingIntrospectorBeanDefinitionRegistryPostProcessor() { return new BeanDefinitionRegistryPostProcessor() { @Override diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java index abc753d3bc..7e31a0ebf9 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.java @@ -303,17 +303,11 @@ public class WebSecurityConfiguration implements ImportAware { * @param filters the Filters to delegate to. One of which must be * FilterChainProxy. */ - @Autowired CompositeFilterChainProxy(List filters) { this.doFilterDelegate = createDoFilterDelegate(filters); this.springSecurityFilterChain = findFilterChainProxy(filters); } - CompositeFilterChainProxy(Filter delegate, FilterChainProxy filterChain) { - this.doFilterDelegate = delegate; - this.springSecurityFilterChain = filterChain; - } - @Override public void afterPropertiesSet() { this.springSecurityFilterChain.afterPropertiesSet(); diff --git a/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java index 5f3e62aaa1..2eda4fb160 100644 --- a/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java +++ b/config/src/main/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHints.java @@ -35,6 +35,9 @@ class WebSecurityConfigurationRuntimeHints implements RuntimeHintsRegistrar { .registerType(TypeReference .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy"), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + hints.reflection() + .registerType(TypeReference.of("org.springframework.web.filter.ServletRequestPathFilter"), + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); } } diff --git a/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java b/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java index 7e94b044b9..d8f1de54c7 100644 --- a/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java +++ b/config/src/test/java/org/springframework/security/config/aot/hint/WebSecurityConfigurationRuntimeHintsTests.java @@ -51,6 +51,9 @@ class WebSecurityConfigurationRuntimeHintsTests { .onType(TypeReference .of("org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy")) .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.hints); + assertThat(RuntimeHintsPredicates.reflection() + .onType(TypeReference.of("org.springframework.web.filter.ServletRequestPathFilter")) + .withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.hints); } } From 0ff3474e2d4a6749414bdc03a81fe1270cb1a5e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 03:21:51 +0000 Subject: [PATCH 063/504] Bump io.micrometer:micrometer-observation from 1.14.5 to 1.14.6 Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.5 to 1.14.6. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.5...v1.14.6) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-observation dependency-version: 1.14.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f8a9091f8a..acd4688dda 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version. com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" -io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.5" +io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" io-mockk = "io.mockk:mockk:1.13.17" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } From eb013944277879b4c1541857a5b8263f5235ff82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 03:41:05 +0000 Subject: [PATCH 064/504] Bump io.projectreactor:reactor-bom from 2023.0.16 to 2023.0.17 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.16 to 2023.0.17. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.16...2023.0.17) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d52e7c45f..21690c33ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.12.13" io-mockk = "io.mockk:mockk:1.13.17" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 757d1c74ba7402c280bebbfcf6ae46345f9aea9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 03:53:46 +0000 Subject: [PATCH 065/504] Bump io.projectreactor:reactor-bom from 2023.0.16 to 2023.0.17 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.16 to 2023.0.17. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.16...2023.0.17) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2caa04a4b4..082f324115 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" io-mockk = "io.mockk:mockk:1.14.0" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From f1a211ae0c89fead61eb8dc86c6bf6426e66e2f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 04:11:12 +0000 Subject: [PATCH 066/504] Bump io.projectreactor:reactor-bom from 2023.0.16 to 2023.0.17 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.16 to 2023.0.17. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.16...2023.0.17) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd4688dda..174cefffca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" io-mockk = "io.mockk:mockk:1.13.17" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.16" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 19090e7873c757080c0ebe21129a03d5866692a3 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Wed, 16 Apr 2025 06:56:15 -0400 Subject: [PATCH 067/504] Add request_uri in OAuth2ParameterNames Closes gh-16947 --- .../oauth2/core/endpoint/OAuth2ParameterNames.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2ParameterNames.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2ParameterNames.java index 49a3fa933f..663bb671a7 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2ParameterNames.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2ParameterNames.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -230,6 +230,13 @@ public final class OAuth2ParameterNames { */ public static final String ACTOR_TOKEN_TYPE = "actor_token_type"; + /** + * {@code request_uri} - used in Pushed Authorization Response and Authorization + * Request. + * @since 6.5 + */ + public static final String REQUEST_URI = "request_uri"; + private OAuth2ParameterNames() { } From c1aa99fdd2113a232986e9c3a44673ae752de840 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Thu, 17 Apr 2025 04:53:33 -0400 Subject: [PATCH 068/504] Enforce BCrypt password length for new passwords only Closes gh-16802 --- .../security/crypto/bcrypt/BCrypt.java | 3 +- .../bcrypt/BCryptPasswordEncoderTests.java | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java index 172928401e..4f19f52de0 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java +++ b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java @@ -611,7 +611,8 @@ public class BCrypt { int rounds, off; StringBuilder rs = new StringBuilder(); - if (passwordb.length > 72) { + // Enforce max length for new passwords only + if (!for_check && passwordb.length > 72) { throw new IllegalArgumentException("password cannot be more than 72 bytes"); } if (salt == null) { diff --git a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java index df14ebe906..f2921064fa 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java @@ -223,13 +223,34 @@ public class BCryptPasswordEncoderTests { } @Test - public void enforcePasswordLength() { + public void encodeWhenPasswordOverMaxLengthThenThrowIllegalArgumentException() { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + String password72chars = "123456789012345678901234567890123456789012345678901234567890123456789012"; - assertThat(encoder.matches(password72chars, encoder.encode(password72chars))).isTrue(); - String password73chars = password72chars.concat("a"); - assertThatIllegalArgumentException() - .isThrownBy(() -> encoder.matches(password73chars, encoder.encode(password73chars))); + encoder.encode(password72chars); + + String password73chars = password72chars + "3"; + assertThatIllegalArgumentException().isThrownBy(() -> encoder.encode(password73chars)); + } + + @Test + public void matchesWhenPasswordOverMaxLengthThenAllowToMatch() { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + String password71chars = "12345678901234567890123456789012345678901234567890123456789012345678901"; + String encodedPassword71chars = "$2a$10$jx3x2FaF.iX5QZ9i3O424Os2Ou5P5JrnedmWYHuDyX8JKA4Unp4xq"; + assertThat(encoder.matches(password71chars, encodedPassword71chars)).isTrue(); + + String password72chars = password71chars + "2"; + String encodedPassword72chars = "$2a$10$oXYO6/UvbsH5rQEraBkl6uheccBqdB3n.RaWbrimog9hS2GX4lo/O"; + assertThat(encoder.matches(password72chars, encodedPassword72chars)).isTrue(); + + // Max length is 72 bytes, however, we need to ensure backwards compatibility + // for previously encoded passwords that are greater than 72 bytes and allow the + // match to be performed. + String password73chars = password72chars + "3"; + String encodedPassword73chars = "$2a$10$1l9.kvQTsqNLiCYFqmKtQOHkp.BrgIrwsnTzWo9jdbQRbuBYQ/AVK"; + assertThat(encoder.matches(password73chars, encodedPassword73chars)).isTrue(); } } From 1516cffb3a6aa6f502a9b64edc9ff060951c1f41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:09:45 +0000 Subject: [PATCH 069/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.11 to 3.2.12 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.11 to 3.2.12. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.11...3.2.12) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 082f324115..d2d01665b5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.4" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.11" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 37402360b6276d82801d55cdc774c14929900dba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:22:04 +0000 Subject: [PATCH 070/504] Bump org.springframework:spring-framework-bom from 6.2.5 to 6.2.6 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.5 to 6.2.6. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.5...v6.2.6) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2d01665b5..d471159f57 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.5" +org-springframework = "6.2.6" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 99c4f58c342cf93e4fe8165dd817aa3be1ba84d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:29:25 +0000 Subject: [PATCH 071/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.11 to 3.2.12 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.11 to 3.2.12. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.11...3.2.12) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 21690c33ae..c56ab2ef7f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.10" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.11" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From a5d963387b8fd7d66000f566f6cae77f8cee0f5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:37:34 +0000 Subject: [PATCH 072/504] Bump org.springframework:spring-framework-bom from 6.1.18 to 6.1.19 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.18 to 6.1.19. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.18...v6.1.19) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c56ab2ef7f..15882887a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.18" +org-springframework = "6.1.19" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 9bcfeab1d68606113d256e1a3defc985866da309 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:45:21 +0000 Subject: [PATCH 073/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.11 to 3.2.12 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.11 to 3.2.12. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.11...3.2.12) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 174cefffca..49c542569f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.4" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.11" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 79bacf8204f1e01c0c7ecae285b33fbb571460b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:44:52 +0000 Subject: [PATCH 074/504] Bump org.springframework:spring-framework-bom from 6.2.5 to 6.2.6 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.5 to 6.2.6. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.5...v6.2.6) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 49c542569f..1bf6c5e9f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.5" +org-springframework = "6.2.6" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From f8d417dc03175f3de9cbe372732d80594c891954 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 21 Apr 2025 08:32:07 -0600 Subject: [PATCH 075/504] Preserve Encrypted Elements Closes gh-16367 --- .../saml2/internal/OpenSaml4Template.java | 12 +--- .../authentication/OpenSaml4Template.java | 12 +--- .../logout/OpenSaml4Template.java | 12 +--- .../service/metadata/OpenSaml4Template.java | 12 +--- .../registration/OpenSaml4Template.java | 12 +--- .../service/web/OpenSaml4Template.java | 12 +--- .../web/authentication/OpenSaml4Template.java | 12 +--- .../logout/OpenSaml4Template.java | 12 +--- .../OpenSaml4AuthenticationProviderTests.java | 60 ++++++++++++++++++- .../saml2/internal/OpenSaml5Template.java | 12 +--- .../authentication/OpenSaml5Template.java | 12 +--- .../logout/OpenSaml5Template.java | 12 +--- .../service/metadata/OpenSaml5Template.java | 12 +--- .../registration/OpenSaml5Template.java | 12 +--- .../service/web/OpenSaml5Template.java | 12 +--- .../web/authentication/OpenSaml5Template.java | 12 +--- .../logout/OpenSaml5Template.java | 12 +--- .../OpenSaml5AuthenticationProviderTests.java | 60 ++++++++++++++++++- 18 files changed, 134 insertions(+), 178 deletions(-) diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java index 002c0862e1..c8df5a3649 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java index f529b8b4a0..4892b7593a 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java index 5344d080dc..f177502cc4 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java index 8cd40194fe..dd1197f95c 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java index a56bcf8100..bb6201b423 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java index b2ca1e1111..db7810cf06 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java index 9ca1253379..62949ae27a 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java index eee4fc8242..399072fc2c 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java index ef45985419..cdccc13c13 100644 --- a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -386,6 +386,24 @@ public class OpenSaml4AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAssertionWithSignatureThenEncryptedAssertionStillAvailable() { + Response response = response(); + Assertion assertion = TestOpenSamlObjects.signed(assertion(), + TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID); + EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + response.getEncryptedAssertions().add(encryptedAssertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setResponseValidator((t) -> { + assertThat(t.getResponse().getEncryptedAssertions()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() { Response response = response(); @@ -410,6 +428,26 @@ public class OpenSaml4AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedNameIdWithSignatureThenEncryptedNameIdStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + NameID nameId = assertion.getSubject().getNameID(); + EncryptedID encryptedID = TestOpenSamlObjects.encrypted(nameId, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + assertion.getSubject().setNameID(null); + assertion.getSubject().setEncryptedID(encryptedID); + response.getAssertions().add(signed(assertion)); + Saml2AuthenticationToken token = token(response, decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getSubject().getEncryptedID()).isNotNull(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAttributeThenDecrypts() { Response response = response(); @@ -426,6 +464,26 @@ public class OpenSaml4AuthenticationProviderTests { assertThat(principal.getAttribute("name")).containsExactly("value"); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAttributeThenEncryptedAttributesStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value", + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME); + statement.getEncryptedAttributes().add(attribute); + assertion.getAttributeStatements().add(statement); + response.getAssertions().add(assertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getAttributeStatements().get(0).getEncryptedAttributes()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() { Response response = response(); diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java index ef74e61c97..fdeffc915a 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java index b2003af461..c5b6ff98ae 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java index d0add4c54c..576bee21dc 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java index e5a39122a3..99b18df8ae 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java index 50f60e5a0d..399fedf577 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java index 73b3d9f391..62da91197a 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java index db40f084ee..305dd60440 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java index 2d095694f5..c7abef6236 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index 22ed0e89b6..284c7a90c3 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -386,6 +386,24 @@ public class OpenSaml5AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAssertionWithSignatureThenEncryptedAssertionStillAvailable() { + Response response = response(); + Assertion assertion = TestOpenSamlObjects.signed(assertion(), + TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID); + EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + response.getEncryptedAssertions().add(encryptedAssertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setResponseValidator((t) -> { + assertThat(t.getResponse().getEncryptedAssertions()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() { Response response = response(); @@ -410,6 +428,26 @@ public class OpenSaml5AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedNameIdWithSignatureThenEncryptedNameIdStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + NameID nameId = assertion.getSubject().getNameID(); + EncryptedID encryptedID = TestOpenSamlObjects.encrypted(nameId, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + assertion.getSubject().setNameID(null); + assertion.getSubject().setEncryptedID(encryptedID); + response.getAssertions().add(signed(assertion)); + Saml2AuthenticationToken token = token(response, decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getSubject().getEncryptedID()).isNotNull(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAttributeThenDecrypts() { Response response = response(); @@ -426,6 +464,26 @@ public class OpenSaml5AuthenticationProviderTests { assertThat(principal.getAttribute("name")).containsExactly("value"); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAttributeThenEncryptedAttributesStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value", + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME); + statement.getEncryptedAttributes().add(attribute); + assertion.getAttributeStatements().add(statement); + response.getAssertions().add(assertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getAttributeStatements().get(0).getEncryptedAttributes()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() { Response response = response(); From 3dd3c1883aeb4a96c1750e46f07ac524c2264370 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 15:58:34 +0000 Subject: [PATCH 076/504] Release 6.5.0-RC1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 88de36ef8d..f7f2a12693 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0-SNAPSHOT +version=6.5.0-RC1 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From f6354250a12b950d00d86bfb1c991d6e82e89a68 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 15:58:56 +0000 Subject: [PATCH 077/504] Release 6.3.9 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d6a97a43fe..c23d79250e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ springBootVersion=3.1.1 -version=6.3.9-SNAPSHOT +version=6.3.9 samplesBranch=6.3.x org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From e8aef09b4fe24337b42dd6556b79523bd550024b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 15:58:58 +0000 Subject: [PATCH 078/504] Release 6.4.5 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e1c210d7c6..6070f29c78 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.5-SNAPSHOT +version=6.4.5 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From b9cae82b892a1b3bed0ccc97ab722b57a3ce0088 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 16:26:30 +0000 Subject: [PATCH 079/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c23d79250e..65a1331cd8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ springBootVersion=3.1.1 -version=6.3.9 +version=6.3.10-SNAPSHOT samplesBranch=6.3.x org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From a4d7ac24c8ab510a42a906ba2aa58fdcd8ef9797 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 16:28:51 +0000 Subject: [PATCH 080/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6070f29c78..5ba0129aa5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.5 +version=6.4.6-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From e47a6714a585b316a9ec36a107a18e39953b1c04 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:44:10 -0500 Subject: [PATCH 081/504] Update to io.spring.gradle:spring-security-release-plugin:1.0.5 Closes gh-6.3.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 15882887a3..27054ae6ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,7 +34,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.4" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.5" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 56a0a54999baf9b15b36491f2cf4ce27261bf03a Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:47:37 -0500 Subject: [PATCH 082/504] Revert "Release 6.5.0-RC1" This reverts commit 3dd3c1883aeb4a96c1750e46f07ac524c2264370. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f7f2a12693..88de36ef8d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0-RC1 +version=6.5.0-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 6273ba5989b9378c1725c9b1e830dff116a577af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 19:01:34 +0000 Subject: [PATCH 083/504] Release 6.5.0-RC1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 88de36ef8d..f7f2a12693 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0-SNAPSHOT +version=6.5.0-RC1 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From fb44fd0c16713786deca1bb1086923c57a491da2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 19:19:09 +0000 Subject: [PATCH 084/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f7f2a12693..88de36ef8d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0-RC1 +version=6.5.0-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 74ec3761f6d1d3cbfa74d888b081fbb0110c6371 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 03:17:09 +0000 Subject: [PATCH 085/504] Bump org.springframework.data:spring-data-bom from 2024.1.4 to 2024.1.5 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.4 to 2024.1.5. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.4...2024.1.5) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f2ab452e65..ad209324e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.4" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.5" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 7bf776ec3839352b070a82c72c231ad4df4b96f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 03:37:48 +0000 Subject: [PATCH 086/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.10 to 2024.0.11. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.10...2024.0.11) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.11 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 27054ae6ee..b80f8aecc3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.10" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.11" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 54cd987dbcad57395ca9373197ff0d36a3bcadf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 03:41:55 +0000 Subject: [PATCH 087/504] Bump org.springframework.data:spring-data-bom from 2024.1.4 to 2024.1.5 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.4 to 2024.1.5. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.4...2024.1.5) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6404f41cd..2236a0cb2b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.4" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.5" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 3f7f3dabe7f4ceebf3d46374668bcc06f351f157 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:28:29 -0600 Subject: [PATCH 088/504] Correct JavaDoc Class Reference --- .../AuthenticationManagerBuilder.java | 4 +--- .../LdapAuthenticationProviderConfigurer.java | 3 +-- .../web/AbstractRequestMatcherRegistry.java | 3 +-- .../DefaultLoginPageConfigurer.java | 9 ------- ...MatcherDelegatingAuthorizationManager.java | 24 +++++++++---------- ...equestMatcherMetadataResponseResolver.java | 3 +-- .../access/ExceptionTranslationFilter.java | 3 +-- .../XFrameOptionsHeaderWriter.java | 7 +++--- 8 files changed, 21 insertions(+), 35 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java index 1368d3c823..12b464a820 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java @@ -67,9 +67,7 @@ public class AuthenticationManagerBuilder /** * Creates a new instance - * @param objectPostProcessor the - * {@link org.springframework.security.config.annotation.ObjectPostProcessor} instance - * to use. + * @param objectPostProcessor the {@link ObjectPostProcessor} instance to use. */ public AuthenticationManagerBuilder(ObjectPostProcessor objectPostProcessor) { super(objectPostProcessor, true); diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java index 7bfc1e9100..c54d6378ec 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java @@ -25,7 +25,6 @@ import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder; -import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; import org.springframework.security.crypto.password.NoOpPasswordEncoder; @@ -133,7 +132,7 @@ public class LdapAuthenticationProviderConfigurer withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { addObjectPostProcessor(objectPostProcessor); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java index 08b35fa8ce..4b9db8bd49 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java @@ -41,7 +41,6 @@ import org.springframework.http.HttpMethod; import org.springframework.lang.Nullable; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.web.ServletRegistrationsSupport.RegistrationMapping; -import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher; @@ -170,7 +169,7 @@ public abstract class AbstractRequestMatcherRegistry { /** * Associates a list of {@link RequestMatcher} instances with the - * {@link AbstractConfigAttributeRequestMatcherRegistry} + * {@link AbstractRequestMatcherRegistry} * @param requestMatchers the {@link RequestMatcher} instances * @return the object that is chained after creating the {@link RequestMatcher} */ diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java index af024ee2d8..babda30e42 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurer.java @@ -33,13 +33,6 @@ import org.springframework.security.web.csrf.CsrfToken; * Adds a Filter that will generate a login page if one is not specified otherwise when * using {@link EnableWebSecurity}. * - *

- * By default an - * {@link org.springframework.security.web.access.channel.InsecureChannelProcessor} and a - * {@link org.springframework.security.web.access.channel.SecureChannelProcessor} will be - * registered. - *

- * *

Security Filters

* * The following Filters are conditionally populated @@ -58,8 +51,6 @@ import org.springframework.security.web.csrf.CsrfToken; * The following shared objects are used: * *
    - *
  • {@link org.springframework.security.web.PortMapper} is used to create the default - * {@link org.springframework.security.web.access.channel.ChannelProcessor} instances
  • *
  • {@link FormLoginConfigurer} is used to determine if the * {@link DefaultLoginPageConfigurer} should be added and how to configure it.
  • *
diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java index 4a2b3de56f..e7ff32718a 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java @@ -155,9 +155,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho /** * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or * {@link PathPatternMessageMatcher} if the application has configured a - * {@link org.springframework.security.messaging.util.matcher.PathPatternMessageMatcherBuilderFactoryBean}) - * instances without regard to the {@link SimpMessageType}. If no destination is - * found on the Message, then the Matcher returns false. + * {@link PathPatternMessageMatcher.Builder} bean) instances without regard to the + * {@link SimpMessageType}. If no destination is found on the Message, then the + * Matcher returns false. * @param patterns the patterns to create {@code MessageMatcher}s from. */ public Builder.Constraint simpDestMatchers(String... patterns) { @@ -167,9 +167,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho /** * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or * {@link PathPatternMessageMatcher} if the application has configured a - * {@link org.springframework.security.messaging.util.matcher.PathPatternMessageMatcherBuilderFactoryBean}) - * instances that match on {@code SimpMessageType.MESSAGE}. If no destination is - * found on the Message, then the Matcher returns false. + * {@link PathPatternMessageMatcher.Builder} bean) instances that match on + * {@code SimpMessageType.MESSAGE}. If no destination is found on the Message, + * then the Matcher returns false. * @param patterns the patterns to create {@code MessageMatcher}s from. */ public Builder.Constraint simpMessageDestMatchers(String... patterns) { @@ -179,9 +179,9 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho /** * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or * {@link PathPatternMessageMatcher} if the application has configured a - * {@link org.springframework.security.messaging.util.matcher.PathPatternMessageMatcherBuilderFactoryBean}) - * instances that match on {@code SimpMessageType.SUBSCRIBE}. If no destination is - * found on the Message, then the Matcher returns false. + * {@link PathPatternMessageMatcher.Builder} bean) instances that match on + * {@code SimpMessageType.SUBSCRIBE}. If no destination is found on the Message, + * then the Matcher returns false. * @param patterns the patterns to create {@code MessageMatcher}s from. */ public Builder.Constraint simpSubscribeDestMatchers(String... patterns) { @@ -189,10 +189,10 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho } /** - * Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances, or + * Maps a {@link List} of {@link SimpDestinationMessageMatcher} (or * {@link PathPatternMessageMatcher} if the application has configured a - * {@link org.springframework.security.messaging.util.matcher.PathPatternMessageMatcherBuilderFactoryBean}. - * If no destination is found on the Message, then the Matcher returns false. + * {@link PathPatternMessageMatcher.Builder} bean) instances. If no destination is + * found on the Message, then the Matcher returns false. * @param type the {@link SimpMessageType} to match on. If null, the * {@link SimpMessageType} is not considered for matching. * @param patterns the patterns to create {@code MessageMatcher}s from. diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/metadata/RequestMatcherMetadataResponseResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/metadata/RequestMatcherMetadataResponseResolver.java index e8348730d2..91ee876b2e 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/metadata/RequestMatcherMetadataResponseResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/metadata/RequestMatcherMetadataResponseResolver.java @@ -62,8 +62,7 @@ public class RequestMatcherMetadataResponseResolver implements Saml2MetadataResp private final Saml2MetadataResolver metadata; /** - * Construct a - * {@link org.springframework.security.saml2.provider.service.metadata.RequestMatcherMetadataResponseResolver} + * Construct a {@link RequestMatcherMetadataResponseResolver} * @param registrations the source for relying party metadata * @param metadata the strategy for converting {@link RelyingPartyRegistration}s into * metadata diff --git a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java index 765fec6ed3..e91ebacc62 100644 --- a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java +++ b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java @@ -56,8 +56,7 @@ import org.springframework.web.filter.GenericFilterBean; *

* If an {@link AuthenticationException} is detected, the filter will launch the * authenticationEntryPoint. This allows common handling of authentication - * failures originating from any subclass of - * {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor}. + * failures originating from Web or Method Security. *

* If an {@link AccessDeniedException} is detected, the filter will determine whether or * not the user is an anonymous user. If they are an anonymous user, the diff --git a/web/src/main/java/org/springframework/security/web/header/writers/frameoptions/XFrameOptionsHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/frameoptions/XFrameOptionsHeaderWriter.java index a3c3f8ad77..ccdbd9e622 100644 --- a/web/src/main/java/org/springframework/security/web/header/writers/frameoptions/XFrameOptionsHeaderWriter.java +++ b/web/src/main/java/org/springframework/security/web/header/writers/frameoptions/XFrameOptionsHeaderWriter.java @@ -30,7 +30,6 @@ import org.springframework.util.Assert; * @author Rob Winch * @author Ankur Pathak * @since 3.2 - * @see AllowFromStrategy */ public final class XFrameOptionsHeaderWriter implements HeaderWriter { @@ -50,8 +49,9 @@ public final class XFrameOptionsHeaderWriter implements HeaderWriter { /** * Creates a new instance * @param frameOptionsMode the {@link XFrameOptionsMode} to use. If using - * {@link XFrameOptionsMode#ALLOW_FROM}, use - * {@link #XFrameOptionsHeaderWriter(AllowFromStrategy)} instead. + * {@link XFrameOptionsMode#ALLOW_FROM}, use Content-Security-Policy with the frame-ancestors + * directive instead. */ public XFrameOptionsHeaderWriter(XFrameOptionsMode frameOptionsMode) { Assert.notNull(frameOptionsMode, "frameOptionsMode cannot be null"); @@ -70,6 +70,7 @@ public final class XFrameOptionsHeaderWriter implements HeaderWriter { * browsers. Instead use Content-Security-Policy with the frame-ancestors * directive. + * @see AllowFromStrategy */ @Deprecated public XFrameOptionsHeaderWriter(AllowFromStrategy allowFromStrategy) { From 2ad859a63c361a9732aa9b325e04bb8e36aa878e Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:37:40 -0600 Subject: [PATCH 089/504] Add Missing Deprecation Markers --- .../config/annotation/rsocket/PayloadInterceptorOrder.java | 4 ++++ .../security/config/method/MethodConfigUtils.java | 3 +++ .../access/hierarchicalroles/RoleHierarchyUtils.java | 2 ++ .../security/access/intercept/NullRunAsManager.java | 2 ++ .../method/PostAuthorizeReactiveAuthorizationManager.java | 3 +++ .../PostFilterAuthorizationReactiveMethodInterceptor.java | 3 +++ .../method/PreAuthorizeReactiveAuthorizationManager.java | 3 +++ .../PreFilterAuthorizationReactiveMethodInterceptor.java | 3 +++ .../BasicAuthenticationPayloadExchangeConverter.java | 2 ++ .../authentication/BearerPayloadExchangeConverter.java | 2 ++ .../web/access/channel/AbstractRetryEntryPoint.java | 4 ++++ .../security/web/access/channel/ChannelEntryPoint.java | 6 ++++++ .../web/access/channel/RetryWithHttpEntryPoint.java | 6 ++++++ .../web/access/channel/RetryWithHttpsEntryPoint.java | 6 ++++++ .../web/context/DelegatingSecurityContextRepository.java | 5 +++++ .../web/context/HttpSessionSecurityContextRepository.java | 2 ++ .../security/web/context/NullSecurityContextRepository.java | 4 ++++ .../context/RequestAttributeSecurityContextRepository.java | 4 ++++ 18 files changed, 64 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/annotation/rsocket/PayloadInterceptorOrder.java b/config/src/main/java/org/springframework/security/config/annotation/rsocket/PayloadInterceptorOrder.java index 4577301714..db9e8fd4ec 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/rsocket/PayloadInterceptorOrder.java +++ b/config/src/main/java/org/springframework/security/config/annotation/rsocket/PayloadInterceptorOrder.java @@ -33,12 +33,16 @@ public enum PayloadInterceptorOrder implements Ordered { /** * Where basic authentication is placed. * @see RSocketSecurity#basicAuthentication(Customizer) + * @deprecated please see {@link PayloadInterceptorOrder#AUTHENTICATION} */ + @Deprecated BASIC_AUTHENTICATION, /** * Where JWT based authentication is performed. * @see RSocketSecurity#jwt(Customizer) + * @deprecated please see {@link PayloadInterceptorOrder#AUTHENTICATION} */ + @Deprecated JWT_AUTHENTICATION, /** * A generic placeholder for other types of authentication. diff --git a/config/src/main/java/org/springframework/security/config/method/MethodConfigUtils.java b/config/src/main/java/org/springframework/security/config/method/MethodConfigUtils.java index d6808633af..e61231b29c 100644 --- a/config/src/main/java/org/springframework/security/config/method/MethodConfigUtils.java +++ b/config/src/main/java/org/springframework/security/config/method/MethodConfigUtils.java @@ -24,6 +24,7 @@ import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.access.vote.AuthenticatedVoter; import org.springframework.security.access.vote.RoleVoter; +import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.config.BeanIds; /** @@ -32,7 +33,9 @@ import org.springframework.security.config.BeanIds; * @author Luke Taylor * @author Ben Alex * @author Rob Winch + * @deprecated Please use {@link AuthorizationManager} instead */ +@Deprecated abstract class MethodConfigUtils { @SuppressWarnings("unchecked") diff --git a/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyUtils.java b/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyUtils.java index 2143632d14..f23add9629 100644 --- a/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyUtils.java +++ b/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyUtils.java @@ -43,7 +43,9 @@ public final class RoleHierarchyUtils { * @return a string representation of a role hierarchy * @throws IllegalArgumentException if roleHierarchyMap is null or empty or if a role * name is null or empty or if an implied role name(s) is null or empty + * @deprecated please see {@link RoleHierarchyImpl#setHierarchy} deprecation notice */ + @Deprecated public static String roleHierarchyFromMap(Map> roleHierarchyMap) { Assert.notEmpty(roleHierarchyMap, "roleHierarchyMap cannot be empty"); StringWriter result = new StringWriter(); diff --git a/core/src/main/java/org/springframework/security/access/intercept/NullRunAsManager.java b/core/src/main/java/org/springframework/security/access/intercept/NullRunAsManager.java index 1cd0bf85d1..36b8ad2157 100644 --- a/core/src/main/java/org/springframework/security/access/intercept/NullRunAsManager.java +++ b/core/src/main/java/org/springframework/security/access/intercept/NullRunAsManager.java @@ -28,7 +28,9 @@ import org.springframework.security.core.Authentication; * functionality. * * @author Ben Alex + * @deprecated please see {@link RunAsManager} deprecation notice */ +@Deprecated final class NullRunAsManager implements RunAsManager { @Override diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java index 2b09d0fd61..e69edcf361 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java @@ -59,7 +59,10 @@ public final class PostAuthorizeReactiveAuthorizationManager * not be resolved. * @param defaults - whether to resolve pre/post-authorization templates parameters * @since 6.3 + * @deprecated please use + * {@link #setTemplateDefaults(AnnotationTemplateExpressionDefaults)} */ + @Deprecated public void setTemplateDefaults(PrePostTemplateDefaults defaults) { this.registry.setTemplateDefaults(defaults); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java index 78079be150..7e37707074 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java @@ -74,7 +74,10 @@ public final class PostFilterAuthorizationReactiveMethodInterceptor implements A * not be resolved. * @param defaults - whether to resolve pre/post-authorization templates parameters * @since 6.3 + * @deprecated please use + * {@link #setTemplateDefaults(AnnotationTemplateExpressionDefaults)} */ + @Deprecated public void setTemplateDefaults(PrePostTemplateDefaults defaults) { this.registry.setTemplateDefaults(defaults); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java index 86829e6020..ddb0eb375d 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java @@ -59,7 +59,10 @@ public final class PreAuthorizeReactiveAuthorizationManager * not be resolved. * @param defaults - whether to resolve pre/post-authorization templates parameters * @since 6.3 + * @deprecated please use + * {@link #setTemplateDefaults(AnnotationTemplateExpressionDefaults)} */ + @Deprecated public void setTemplateDefaults(PrePostTemplateDefaults defaults) { this.registry.setTemplateDefaults(defaults); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java index 2b9f9a4894..4f2267c3cb 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java @@ -77,7 +77,10 @@ public final class PreFilterAuthorizationReactiveMethodInterceptor implements Au * not be resolved. * @param defaults - whether to resolve pre/post-authorization templates parameters * @since 6.3 + * @deprecated please use + * {@link #setTemplateDefaults(AnnotationTemplateExpressionDefaults)} */ + @Deprecated public void setTemplateDefaults(PrePostTemplateDefaults defaults) { this.registry.setTemplateDefaults(defaults); } diff --git a/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BasicAuthenticationPayloadExchangeConverter.java b/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BasicAuthenticationPayloadExchangeConverter.java index bab31bd630..8ff0749475 100644 --- a/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BasicAuthenticationPayloadExchangeConverter.java +++ b/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BasicAuthenticationPayloadExchangeConverter.java @@ -36,7 +36,9 @@ import org.springframework.util.MimeTypeUtils; * * @author Rob Winch * @since 5.2 + * @deprecated please use {@link AuthenticationPayloadExchangeConverter} instead */ +@Deprecated public class BasicAuthenticationPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter { private MimeType metadataMimetype = MimeTypeUtils diff --git a/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BearerPayloadExchangeConverter.java b/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BearerPayloadExchangeConverter.java index cdaca17264..09d02452e8 100644 --- a/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BearerPayloadExchangeConverter.java +++ b/rsocket/src/main/java/org/springframework/security/rsocket/authentication/BearerPayloadExchangeConverter.java @@ -34,7 +34,9 @@ import org.springframework.security.rsocket.metadata.BearerTokenMetadata; * * @author Rob Winch * @since 5.2 + * @deprecated please use {@link AuthenticationPayloadExchangeConverter} instead */ +@Deprecated public class BearerPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter { private static final String BEARER_MIME_TYPE_VALUE = BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE.toString(); diff --git a/web/src/main/java/org/springframework/security/web/access/channel/AbstractRetryEntryPoint.java b/web/src/main/java/org/springframework/security/web/access/channel/AbstractRetryEntryPoint.java index ad0346d4aa..4af85191e4 100644 --- a/web/src/main/java/org/springframework/security/web/access/channel/AbstractRetryEntryPoint.java +++ b/web/src/main/java/org/springframework/security/web/access/channel/AbstractRetryEntryPoint.java @@ -34,7 +34,11 @@ import org.springframework.util.Assert; /** * @author Luke Taylor + * @deprecated please use + * {@link org.springframework.security.web.transport.HttpsRedirectFilter} and its + * associated {@link PortMapper} */ +@Deprecated public abstract class AbstractRetryEntryPoint implements ChannelEntryPoint { protected final Log logger = LogFactory.getLog(getClass()); diff --git a/web/src/main/java/org/springframework/security/web/access/channel/ChannelEntryPoint.java b/web/src/main/java/org/springframework/security/web/access/channel/ChannelEntryPoint.java index f5149055bf..405b861179 100644 --- a/web/src/main/java/org/springframework/security/web/access/channel/ChannelEntryPoint.java +++ b/web/src/main/java/org/springframework/security/web/access/channel/ChannelEntryPoint.java @@ -22,6 +22,8 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.web.PortMapper; + /** * May be used by a {@link ChannelProcessor} to launch a web channel. * @@ -31,7 +33,11 @@ import jakarta.servlet.http.HttpServletResponse; * interface to assist ChannelProcessors in performing this delegation. * * @author Ben Alex + * @deprecated please use + * {@link org.springframework.security.web.transport.HttpsRedirectFilter} and its + * associated {@link PortMapper} */ +@Deprecated public interface ChannelEntryPoint { /** diff --git a/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpEntryPoint.java b/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpEntryPoint.java index 27fcf7deb8..a4cd77fd81 100644 --- a/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpEntryPoint.java +++ b/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpEntryPoint.java @@ -16,6 +16,8 @@ package org.springframework.security.web.access.channel; +import org.springframework.security.web.PortMapper; + /** * Commences an insecure channel by retrying the original request using HTTP. *

@@ -24,7 +26,11 @@ package org.springframework.security.web.access.channel; * issue. * * @author Ben Alex + * @deprecated please use + * {@link org.springframework.security.web.transport.HttpsRedirectFilter} and its + * associated {@link PortMapper} */ +@Deprecated(since = "6.5") public class RetryWithHttpEntryPoint extends AbstractRetryEntryPoint { public RetryWithHttpEntryPoint() { diff --git a/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpsEntryPoint.java b/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpsEntryPoint.java index 7b13ab2fd5..c7e113ac67 100644 --- a/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpsEntryPoint.java +++ b/web/src/main/java/org/springframework/security/web/access/channel/RetryWithHttpsEntryPoint.java @@ -16,6 +16,8 @@ package org.springframework.security.web.access.channel; +import org.springframework.security.web.PortMapper; + /** * Commences a secure channel by retrying the original request using HTTPS. *

@@ -25,7 +27,11 @@ package org.springframework.security.web.access.channel; *

* * @author Ben Alex + * @deprecated please use + * {@link org.springframework.security.web.transport.HttpsRedirectFilter} and its + * associated {@link PortMapper} */ +@Deprecated(since = "6.5") public class RetryWithHttpsEntryPoint extends AbstractRetryEntryPoint { public RetryWithHttpsEntryPoint() { diff --git a/web/src/main/java/org/springframework/security/web/context/DelegatingSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/DelegatingSecurityContextRepository.java index 10c6d1e429..7a5eb98336 100644 --- a/web/src/main/java/org/springframework/security/web/context/DelegatingSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/DelegatingSecurityContextRepository.java @@ -44,7 +44,12 @@ public final class DelegatingSecurityContextRepository implements SecurityContex this.delegates = delegates; } + /** + * @deprecated + * @see SecurityContextRepository#loadContext + */ @Override + @Deprecated public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { SecurityContext result = null; for (SecurityContextRepository delegate : this.delegates) { diff --git a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java index 3edacbd7ac..1eec20e161 100644 --- a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java @@ -115,7 +115,9 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo * If the session is null, the context object is null or the context object stored in * the session is not an instance of {@code SecurityContext}, a new context object * will be generated and returned. + * @deprecated please see {@link SecurityContextRepository#loadContext} */ + @Deprecated @Override public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { HttpServletRequest request = requestResponseHolder.getRequest(); diff --git a/web/src/main/java/org/springframework/security/web/context/NullSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/NullSecurityContextRepository.java index e0a916f46e..3d1a4eca39 100644 --- a/web/src/main/java/org/springframework/security/web/context/NullSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/NullSecurityContextRepository.java @@ -38,7 +38,11 @@ public final class NullSecurityContextRepository implements SecurityContextRepos return false; } + /** + * @deprecated please see {@link SecurityContextRepository#loadContext} + */ @Override + @Deprecated public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { return this.securityContextHolderStrategy.createEmptyContext(); } diff --git a/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java index 2080c61d55..daf9b21bd4 100644 --- a/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java @@ -75,7 +75,11 @@ public final class RequestAttributeSecurityContextRepository implements Security return getContext(request) != null; } + /** + * @deprecated please see {@link SecurityContextRepository#loadContext} + */ @Override + @Deprecated public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { return loadDeferredContext(requestResponseHolder.getRequest()).get(); } From 216680bb5048f2b66b27e673be03706223d35933 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:34:22 -0600 Subject: [PATCH 090/504] Update Deprecated Spring Jdbc Usage --- .../security/acls/jdbc/JdbcAclService.java | 4 +- .../acls/jdbc/JdbcMutableAclService.java | 7 +- .../acls/jdbc/JdbcAclServiceTests.java | 2 +- .../core/userdetails/jdbc/JdbcDaoImpl.java | 13 ++-- .../provisioning/JdbcUserDetailsManager.java | 8 +-- .../JdbcUserCredentialRepository.java | 64 ++++++++++++------- 6 files changed, 55 insertions(+), 43 deletions(-) diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java index e499577388..f8dbb687e6 100644 --- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java +++ b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java @@ -100,8 +100,8 @@ public class JdbcAclService implements AclService { @Override public List findChildren(ObjectIdentity parentIdentity) { Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() }; - List objects = this.jdbcOperations.query(this.findChildrenSql, args, - (rs, rowNum) -> mapObjectIdentityRow(rs)); + List objects = this.jdbcOperations.query(this.findChildrenSql, + (rs, rowNum) -> mapObjectIdentityRow(rs), args); return (!objects.isEmpty()) ? objects : null; } diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java index 93f68dd3e7..9b8eb5acbc 100644 --- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java +++ b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java @@ -190,8 +190,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS * @return the primary key or null if not found */ protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) { - List classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type }, - Long.class); + List classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type); if (!classIds.isEmpty()) { return classIds.get(0); @@ -242,8 +241,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS * @return the primary key or null if not found */ protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) { - List sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, - new Object[] { sidIsPrincipal, sidName }, Long.class); + List sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey, Long.class, sidIsPrincipal, + sidName); if (!sidIds.isEmpty()) { return sidIds.get(0); } diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java index 6253c29702..60feb59220 100644 --- a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java +++ b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcAclServiceTests.java @@ -109,7 +109,7 @@ public class JdbcAclServiceTests { List result = new ArrayList<>(); result.add(new ObjectIdentityImpl(Object.class, "5577")); Object[] args = { "1", "org.springframework.security.acls.jdbc.JdbcAclServiceTests$MockLongIdDomainObject" }; - given(this.jdbcOperations.query(anyString(), eq(args), any(RowMapper.class))).willReturn(result); + given(this.jdbcOperations.query(anyString(), any(RowMapper.class), eq(args))).willReturn(result); ObjectIdentity objectIdentity = new ObjectIdentityImpl(MockLongIdDomainObject.class, 1L); List objectIdentities = this.aclService.findChildren(objectIdentity); assertThat(objectIdentities).hasSize(1); diff --git a/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java b/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java index 9772cf8a62..582fddb2f4 100644 --- a/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java +++ b/core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java @@ -226,10 +226,10 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService, M * @return a list of GrantedAuthority objects for the user */ protected List loadUserAuthorities(String username) { - return getJdbcTemplate().query(this.authoritiesByUsernameQuery, new String[] { username }, (rs, rowNum) -> { + return getJdbcTemplate().query(this.authoritiesByUsernameQuery, (rs, rowNum) -> { String roleName = JdbcDaoImpl.this.rolePrefix + rs.getString(2); return new SimpleGrantedAuthority(roleName); - }); + }, username); } /** @@ -238,11 +238,10 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService, M * @return a list of GrantedAuthority objects for the user */ protected List loadGroupAuthorities(String username) { - return getJdbcTemplate().query(this.groupAuthoritiesByUsernameQuery, new String[] { username }, - (rs, rowNum) -> { - String roleName = getRolePrefix() + rs.getString(3); - return new SimpleGrantedAuthority(roleName); - }); + return getJdbcTemplate().query(this.groupAuthoritiesByUsernameQuery, (rs, rowNum) -> { + String roleName = getRolePrefix() + rs.getString(3); + return new SimpleGrantedAuthority(roleName); + }, username); } /** diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index a32c1a87da..b5f80e2946 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -336,8 +336,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public boolean userExists(String username) { - List users = getJdbcTemplate().queryForList(this.userExistsSql, new String[] { username }, - String.class); + List users = getJdbcTemplate().queryForList(this.userExistsSql, String.class, username); if (users.size() > 1) { throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1); @@ -353,7 +352,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public List findUsersInGroup(String groupName) { Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().queryForList(this.findUsersInGroupSql, new String[] { groupName }, String.class); + return getJdbcTemplate().queryForList(this.findUsersInGroupSql, String.class, groupName); } @Override @@ -422,8 +421,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa public List findGroupAuthorities(String groupName) { this.logger.debug("Loading authorities for group '" + groupName + "'"); Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().query(this.groupAuthoritiesSql, new String[] { groupName }, - this.grantedAuthorityMapper); + return getJdbcTemplate().query(this.groupAuthoritiesSql, this.grantedAuthorityMapper, groupName); } private GrantedAuthority mapToGrantedAuthority(ResultSet rs, int rowNum) throws SQLException { diff --git a/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java b/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java index 660daf6008..2ce023afe1 100644 --- a/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java +++ b/web/src/main/java/org/springframework/security/web/webauthn/management/JdbcUserCredentialRepository.java @@ -33,7 +33,6 @@ import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SqlParameterValue; -import org.springframework.jdbc.support.lob.DefaultLobHandler; import org.springframework.jdbc.support.lob.LobCreator; import org.springframework.jdbc.support.lob.LobHandler; import org.springframework.security.web.webauthn.api.AuthenticatorTransport; @@ -62,11 +61,11 @@ import org.springframework.util.CollectionUtils; */ public final class JdbcUserCredentialRepository implements UserCredentialRepository { - private RowMapper credentialRecordRowMapper = new CredentialRecordRowMapper(); + private RowMapper credentialRecordRowMapper = new CredentialRecordRowMapper(ResultSet::getBytes); private Function> credentialRecordParametersMapper = new CredentialRecordParametersMapper(); - private LobHandler lobHandler = new DefaultLobHandler(); + private SetBytes setBytes = PreparedStatement::setBytes; private final JdbcOperations jdbcOperations; @@ -159,22 +158,16 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit private void insertCredentialRecord(CredentialRecord record) { List parameters = this.credentialRecordParametersMapper.apply(record); - try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { - PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, - parameters.toArray()); - this.jdbcOperations.update(SAVE_CREDENTIAL_RECORD_SQL, pss); - } + PreparedStatementSetter pss = new BlobArgumentPreparedStatementSetter(this.setBytes, parameters.toArray()); + this.jdbcOperations.update(SAVE_CREDENTIAL_RECORD_SQL, pss); } private int updateCredentialRecord(CredentialRecord record) { List parameters = this.credentialRecordParametersMapper.apply(record); SqlParameterValue credentialId = parameters.remove(0); parameters.add(credentialId); - try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { - PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, - parameters.toArray()); - return this.jdbcOperations.update(UPDATE_CREDENTIAL_RECORD_SQL, pss); - } + PreparedStatementSetter pss = new BlobArgumentPreparedStatementSetter(this.setBytes, parameters.toArray()); + return this.jdbcOperations.update(UPDATE_CREDENTIAL_RECORD_SQL, pss); } @Override @@ -195,10 +188,18 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit /** * Sets a {@link LobHandler} for large binary fields and large text field parameters. * @param lobHandler the lob handler + * @deprecated {@link LobHandler} is deprecated without replacement, as such this + * method will also be removed without replacement */ + @Deprecated(since = "6.5", forRemoval = true) public void setLobHandler(LobHandler lobHandler) { Assert.notNull(lobHandler, "lobHandler cannot be null"); - this.lobHandler = lobHandler; + this.setBytes = (ps, index, bytes) -> { + try (LobCreator creator = lobHandler.getLobCreator()) { + creator.setBlobAsBytes(ps, index, bytes); + } + }; + this.credentialRecordRowMapper = new CredentialRecordRowMapper(lobHandler::getBlobAsBytes); } private static class CredentialRecordParametersMapper @@ -246,13 +247,25 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit } - private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter { + private interface SetBytes { - private final LobCreator lobCreator; + void setBytes(PreparedStatement ps, int index, byte[] bytes) throws SQLException; - private LobCreatorArgumentPreparedStatementSetter(LobCreator lobCreator, Object[] args) { + } + + private interface GetBytes { + + byte[] getBytes(ResultSet rs, String columnName) throws SQLException; + + } + + private static final class BlobArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter { + + private final SetBytes setBytes; + + private BlobArgumentPreparedStatementSetter(SetBytes setBytes, Object[] args) { super(args); - this.lobCreator = lobCreator; + this.setBytes = setBytes; } @Override @@ -264,7 +277,7 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit "Value of blob parameter must be byte[]"); } byte[] valueBytes = (byte[]) paramValue.getValue(); - this.lobCreator.setBlobAsBytes(ps, parameterPosition, valueBytes); + this.setBytes.setBytes(ps, parameterPosition, valueBytes); return; } } @@ -275,14 +288,17 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit private static class CredentialRecordRowMapper implements RowMapper { - private LobHandler lobHandler = new DefaultLobHandler(); + private final GetBytes getBytes; + + CredentialRecordRowMapper(GetBytes getBytes) { + this.getBytes = getBytes; + } @Override public CredentialRecord mapRow(ResultSet rs, int rowNum) throws SQLException { Bytes credentialId = Bytes.fromBase64(new String(rs.getString("credential_id").getBytes())); Bytes userEntityUserId = Bytes.fromBase64(new String(rs.getString("user_entity_user_id").getBytes())); - ImmutablePublicKeyCose publicKey = new ImmutablePublicKeyCose( - this.lobHandler.getBlobAsBytes(rs, "public_key")); + ImmutablePublicKeyCose publicKey = new ImmutablePublicKeyCose(this.getBytes.getBytes(rs, "public_key")); long signatureCount = rs.getLong("signature_count"); boolean uvInitialized = rs.getBoolean("uv_initialized"); boolean backupEligible = rs.getBoolean("backup_eligible"); @@ -291,13 +307,13 @@ public final class JdbcUserCredentialRepository implements UserCredentialReposit boolean backupState = rs.getBoolean("backup_state"); Bytes attestationObject = null; - byte[] rawAttestationObject = this.lobHandler.getBlobAsBytes(rs, "attestation_object"); + byte[] rawAttestationObject = this.getBytes.getBytes(rs, "attestation_object"); if (rawAttestationObject != null) { attestationObject = new Bytes(rawAttestationObject); } Bytes attestationClientDataJson = null; - byte[] rawAttestationClientDataJson = this.lobHandler.getBlobAsBytes(rs, "attestation_client_data_json"); + byte[] rawAttestationClientDataJson = this.getBytes.getBytes(rs, "attestation_client_data_json"); if (rawAttestationClientDataJson != null) { attestationClientDataJson = new Bytes(rawAttestationClientDataJson); } From 834370d8eb766cfcf35815179a14df4866d7b362 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 23 Apr 2025 11:28:20 -0600 Subject: [PATCH 091/504] Update Deprecated Spring Web Usage --- .../client/OidcBackChannelLogoutHandler.java | 2 +- .../OidcClientInitiatedLogoutSuccessHandler.java | 2 +- ...DefaultOAuth2AuthorizationRequestResolver.java | 2 +- .../web/OAuth2LoginAuthenticationFilter.java | 2 +- ...th2AuthorizedClientExchangeFilterFunction.java | 15 ++++++++------- ...th2AuthorizedClientExchangeFilterFunction.java | 15 ++++++++------- ...yingPartyRegistrationPlaceholderResolvers.java | 4 ++-- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutHandler.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutHandler.java index d7348f5c09..505b354ea8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutHandler.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutHandler.java @@ -127,7 +127,7 @@ public final class OidcBackChannelLogoutHandler implements LogoutHandler { String computeLogoutEndpoint(HttpServletRequest request, OidcBackChannelLogoutAuthentication token) { // @formatter:off UriComponents uriComponents = UriComponentsBuilder - .fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + .fromUriString(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java index 5125c988dc..6e26f80d4a 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java @@ -95,7 +95,7 @@ public class OidcClientInitiatedLogoutSuccessHandler extends SimpleUrlLogoutSucc } // @formatter:off UriComponents uriComponents = UriComponentsBuilder - .fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + .fromUriString(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java index 63a78649ce..a2297accd7 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java @@ -226,7 +226,7 @@ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2Au Map uriVariables = new HashMap<>(); uriVariables.put("registrationId", clientRegistration.getRegistrationId()); // @formatter:off - UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + UriComponents uriComponents = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java index cb51be66dc..b456ca48a1 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java @@ -184,7 +184,7 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); } // @formatter:off - String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + String redirectUri = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) .replaceQuery(null) .build() .toUriString(); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java index ca20a6d7cf..2d9be5ebf4 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java @@ -29,6 +29,7 @@ import reactor.core.publisher.Mono; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.AuthorityUtils; @@ -469,7 +470,7 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements * A map of HTTP Status Code to OAuth 2.0 Error codes for HTTP status codes that * should be interpreted as authentication or authorization failures. */ - private final Map httpStatusToOAuth2ErrorCodeMap; + private final Map httpStatusToOAuth2ErrorCodeMap; /** * The {@link ReactiveOAuth2AuthorizationFailureHandler} to notify when an @@ -480,9 +481,9 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements private AuthorizationFailureForwarder(ReactiveOAuth2AuthorizationFailureHandler authorizationFailureHandler) { Assert.notNull(authorizationFailureHandler, "authorizationFailureHandler cannot be null"); this.authorizationFailureHandler = authorizationFailureHandler; - Map httpStatusToOAuth2Error = new HashMap<>(); - httpStatusToOAuth2Error.put(HttpStatus.UNAUTHORIZED.value(), OAuth2ErrorCodes.INVALID_TOKEN); - httpStatusToOAuth2Error.put(HttpStatus.FORBIDDEN.value(), OAuth2ErrorCodes.INSUFFICIENT_SCOPE); + Map httpStatusToOAuth2Error = new HashMap<>(); + httpStatusToOAuth2Error.put(HttpStatus.UNAUTHORIZED, OAuth2ErrorCodes.INVALID_TOKEN); + httpStatusToOAuth2Error.put(HttpStatus.FORBIDDEN, OAuth2ErrorCodes.INSUFFICIENT_SCOPE); this.httpStatusToOAuth2ErrorCodeMap = Collections.unmodifiableMap(httpStatusToOAuth2Error); } @@ -525,10 +526,10 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements authParameters.get(OAuth2ParameterNames.ERROR_URI)); } } - return resolveErrorIfPossible(response.statusCode().value()); + return resolveErrorIfPossible(response.statusCode()); } - private OAuth2Error resolveErrorIfPossible(int statusCode) { + private OAuth2Error resolveErrorIfPossible(HttpStatusCode statusCode) { if (this.httpStatusToOAuth2ErrorCodeMap.containsKey(statusCode)) { return new OAuth2Error(this.httpStatusToOAuth2ErrorCodeMap.get(statusCode), null, "https://tools.ietf.org/html/rfc6750#section-3.1"); @@ -563,7 +564,7 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements */ private Mono handleWebClientResponseException(ClientRequest request, WebClientResponseException exception) { - return Mono.justOrEmpty(resolveErrorIfPossible(exception.getRawStatusCode())).flatMap((oauth2Error) -> { + return Mono.justOrEmpty(resolveErrorIfPossible(exception.getStatusCode())).flatMap((oauth2Error) -> { Mono> serverWebExchange = effectiveServerWebExchange(request); Mono clientRegistrationId = effectiveClientRegistrationId(request); return Mono diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java index d214c87d84..db136ba11b 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java @@ -32,6 +32,7 @@ import reactor.util.context.Context; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; @@ -585,7 +586,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement * A map of HTTP status code to OAuth 2.0 error code for HTTP status codes that * should be interpreted as authentication or authorization failures. */ - private final Map httpStatusToOAuth2ErrorCodeMap; + private final Map httpStatusToOAuth2ErrorCodeMap; /** * The {@link OAuth2AuthorizationFailureHandler} to notify when an @@ -596,9 +597,9 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement private AuthorizationFailureForwarder(OAuth2AuthorizationFailureHandler authorizationFailureHandler) { Assert.notNull(authorizationFailureHandler, "authorizationFailureHandler cannot be null"); this.authorizationFailureHandler = authorizationFailureHandler; - Map httpStatusToOAuth2Error = new HashMap<>(); - httpStatusToOAuth2Error.put(HttpStatus.UNAUTHORIZED.value(), OAuth2ErrorCodes.INVALID_TOKEN); - httpStatusToOAuth2Error.put(HttpStatus.FORBIDDEN.value(), OAuth2ErrorCodes.INSUFFICIENT_SCOPE); + Map httpStatusToOAuth2Error = new HashMap<>(); + httpStatusToOAuth2Error.put(HttpStatus.UNAUTHORIZED, OAuth2ErrorCodes.INVALID_TOKEN); + httpStatusToOAuth2Error.put(HttpStatus.FORBIDDEN, OAuth2ErrorCodes.INSUFFICIENT_SCOPE); this.httpStatusToOAuth2ErrorCodeMap = Collections.unmodifiableMap(httpStatusToOAuth2Error); } @@ -641,10 +642,10 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement authParameters.get(OAuth2ParameterNames.ERROR_URI)); } } - return resolveErrorIfPossible(response.statusCode().value()); + return resolveErrorIfPossible(response.statusCode()); } - private OAuth2Error resolveErrorIfPossible(int statusCode) { + private OAuth2Error resolveErrorIfPossible(HttpStatusCode statusCode) { if (this.httpStatusToOAuth2ErrorCodeMap.containsKey(statusCode)) { return new OAuth2Error(this.httpStatusToOAuth2ErrorCodeMap.get(statusCode), null, "https://tools.ietf.org/html/rfc6750#section-3.1"); @@ -678,7 +679,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement */ private Mono handleWebClientResponseException(ClientRequest request, WebClientResponseException exception) { - return Mono.justOrEmpty(resolveErrorIfPossible(exception.getRawStatusCode())).flatMap((oauth2Error) -> { + return Mono.justOrEmpty(resolveErrorIfPossible(exception.getStatusCode())).flatMap((oauth2Error) -> { Map attrs = request.attributes(); OAuth2AuthorizedClient authorizedClient = getOAuth2AuthorizedClient(attrs); if (authorizedClient == null) { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/RelyingPartyRegistrationPlaceholderResolvers.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/RelyingPartyRegistrationPlaceholderResolvers.java index 4a39f151cd..03d282b22c 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/RelyingPartyRegistrationPlaceholderResolvers.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/RelyingPartyRegistrationPlaceholderResolvers.java @@ -82,7 +82,7 @@ public final class RelyingPartyRegistrationPlaceholderResolvers { private static Map uriVariables(HttpServletRequest request) { String baseUrl = getApplicationUri(request); Map uriVariables = new HashMap<>(); - UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl) + UriComponents uriComponents = UriComponentsBuilder.fromUriString(baseUrl) .replaceQuery(null) .fragment(null) .build(); @@ -103,7 +103,7 @@ public final class RelyingPartyRegistrationPlaceholderResolvers { } private static String getApplicationUri(HttpServletRequest request) { - UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + UriComponents uriComponents = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) .replacePath(request.getContextPath()) .replaceQuery(null) .fragment(null) From eecd7d955939625e18698c5791ca864c131df947 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:31:58 -0600 Subject: [PATCH 092/504] Update Deprecated Reactor Usage --- ...actWebClientReactiveOAuth2AccessTokenResponseClient.java | 4 +--- .../SpringReactiveOpaqueTokenIntrospector.java | 5 ++--- .../SpringReactiveOpaqueTokenIntrospectorTests.java | 6 +++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java index 5bee19372f..b92e050c80 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractWebClientReactiveOAuth2AccessTokenResponseClient.java @@ -84,9 +84,7 @@ public abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient this.requestEntityConverter.convert(grantRequest) - .exchange() - .flatMap((response) -> response.body(this.bodyExtractor)) - ); + .exchangeToMono((response) -> response.body(this.bodyExtractor))); // @formatter:on } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java index 283317f95e..bdd3f8d634 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java @@ -105,7 +105,6 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke // @formatter:off return Mono.just(token) .flatMap(this::makeRequest) - .flatMap(this::adaptToNimbusResponse) .map(this::convertClaimsSet) .flatMap(this.authenticationConverter::convert) .cast(OAuth2AuthenticatedPrincipal.class) @@ -113,13 +112,13 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke // @formatter:on } - private Mono makeRequest(String token) { + private Mono> makeRequest(String token) { // @formatter:off return this.webClient.post() .uri(this.introspectionUri) .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .body(BodyInserters.fromFormData("token", token)) - .exchange(); + .exchangeToMono(this::adaptToNimbusResponse); // @formatter:on } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java index 8fe1298360..da9d22df23 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.mockwebserver.Dispatcher; @@ -322,7 +323,10 @@ public class SpringReactiveOpaqueTokenIntrospectorTests { ClientResponse.Headers headers = mock(ClientResponse.Headers.class); given(headers.contentType()).willReturn(Optional.of(MediaType.APPLICATION_JSON)); given(clientResponse.headers()).willReturn(headers); - given(spec.exchange()).willReturn(Mono.just(clientResponse)); + given(spec.exchangeToMono(any())).willAnswer((invocation) -> { + Function> fun = invocation.getArgument(0); + return fun.apply(clientResponse); + }); return webClient; } From 0ab01eac149f21cc143afd4c5a8a870e905cfea0 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 15:30:33 -0600 Subject: [PATCH 093/504] Update Deprecated Security Usage --- .../config/annotation/web/builders/WebSecurity.java | 3 ++- .../http/OAuth2ResourceServerBeanDefinitionParser.java | 4 ++-- .../security/config/web/server/ServerHttpSecurity.java | 4 ++-- .../PublicKeyCredentialCreationOptionsFilter.java | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java index 329859a1f5..9b906ebdfd 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java @@ -385,7 +385,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder authorizationManager = authorization.getAuthorizationManager(); builder.add(securityFilterChain::matches, - (authentication, context) -> authorizationManager.check(authentication, context.getRequest())); + (authentication, context) -> (AuthorizationDecision) authorizationManager + .authorize(authentication, context.getRequest())); mappings = true; } } diff --git a/config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java index 58b896c32b..4fd3d12948 100644 --- a/config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParser.java @@ -40,7 +40,7 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; -import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; +import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; @@ -300,7 +300,7 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa String clientId = element.getAttribute(CLIENT_ID); String clientSecret = element.getAttribute(CLIENT_SECRET); BeanDefinitionBuilder introspectorBuilder = BeanDefinitionBuilder - .rootBeanDefinition(NimbusOpaqueTokenIntrospector.class); + .rootBeanDefinition(SpringOpaqueTokenIntrospector.class); introspectorBuilder.addConstructorArgValue(introspectionUri); introspectorBuilder.addConstructorArgValue(clientId); introspectorBuilder.addConstructorArgValue(clientSecret); diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index fbe5bfb903..dd25029229 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -2736,7 +2736,7 @@ public class ServerHttpSecurity { ServerHttpSecurity.this.defaultEntryPoints.add(new DelegateEntry(preferredMatcher, this.entryPoint)); AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(this.authenticationManager); authenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler()); - authenticationFilter.setAuthenticationConverter(new ServerHttpBasicAuthenticationConverter()); + authenticationFilter.setServerAuthenticationConverter(new ServerHttpBasicAuthenticationConverter()); authenticationFilter.setSecurityContextRepository(this.securityContextRepository); authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http)); http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.HTTP_BASIC); @@ -3014,7 +3014,7 @@ public class ServerHttpSecurity { AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(this.authenticationManager); authenticationFilter.setRequiresAuthenticationMatcher(this.requiresAuthenticationMatcher); authenticationFilter.setAuthenticationFailureHandler(this.authenticationFailureHandler); - authenticationFilter.setAuthenticationConverter(new ServerFormLoginAuthenticationConverter()); + authenticationFilter.setServerAuthenticationConverter(new ServerFormLoginAuthenticationConverter()); authenticationFilter.setAuthenticationSuccessHandler(getAuthenticationSuccessHandler(http)); authenticationFilter.setSecurityContextRepository(this.securityContextRepository); http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN); diff --git a/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java b/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java index 1e93cb3502..5a695a1f0b 100644 --- a/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java +++ b/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java @@ -32,8 +32,8 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.security.authorization.AuthenticatedAuthorizationManager; -import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -104,8 +104,8 @@ public class PublicKeyCredentialCreationOptionsFilter extends OncePerRequestFilt Supplier context = this.securityContextHolderStrategy.getDeferredContext(); Supplier authentication = () -> context.get().getAuthentication(); - AuthorizationDecision decision = this.authorization.check(authentication, request); - if (!decision.isGranted()) { + AuthorizationResult result = this.authorization.authorize(authentication, request); + if (!result.isGranted()) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return; } From 61d6fbc2a91a59fc777c8e7884a73b149a61e3f9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:44:01 -0600 Subject: [PATCH 094/504] Update Documentation for PathPatternRequestMatcher Issue gh-16765 --- docs/modules/ROOT/pages/migration-7/web.adoc | 6 +++--- .../servlet/authorization/authorize-http-requests.adoc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc index 330d87ddc2..467f2663e8 100644 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ b/docs/modules/ROOT/pages/migration-7/web.adoc @@ -401,7 +401,7 @@ Instead of taking this responsibility away from developers, now it is simpler to [method,java] ---- -PathPatternRequestParser.Builder servlet = PathPatternRequestParser.servletPath("/mvc"); +PathPatternRequestParser.Builder servlet = PathPatternRequestParser.withDefaults().basePath("/mvc"); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated() @@ -409,11 +409,11 @@ http ---- -For paths that belong to the default servlet, use `PathPatternRequestParser.path()` instead: +For paths that belong to the default servlet, use `PathPatternRequestParser.withDefaults()` instead: [method,java] ---- -PathPatternRequestParser.Builder request = PathPatternRequestParser.path(); +PathPatternRequestParser.Builder request = PathPatternRequestParser.withDefaults(); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(request.pattern("/js/**").matcher()).authenticated() diff --git a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc index 584c85da47..ca3fd6b2bf 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc @@ -594,7 +594,7 @@ import static org.springframework.security.web.servlet.util.matcher.PathPatternR @Bean SecurityFilterChain appEndpoints(HttpSecurity http) { - PathPatternRequestMatcher.Builder mvc = withDefaults().servletPath("/spring-mvc"); + PathPatternRequestMatcher.Builder mvc = withDefaults().basePath("/spring-mvc"); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(mvc.matcher("/admin/**")).hasAuthority("admin") From bc9ae1eed6afa997e1f68e4aeadafb78a1b79c3a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:37:47 -0600 Subject: [PATCH 095/504] Improve NPE Handling --- .../provisioning/JdbcUserDetailsManager.java | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index b5f80e2946..59c0147da5 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -29,6 +29,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContextException; import org.springframework.core.log.LogMessage; import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.RowMapper; import org.springframework.security.access.AccessDeniedException; @@ -214,7 +215,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa */ @Override protected List loadUsersByUsername(String username) { - return getJdbcTemplate().query(getUsersByUsernameQuery(), this.userDetailsMapper, username); + return requireJdbcTemplate().query(getUsersByUsernameQuery(), this.userDetailsMapper, username); } private UserDetails mapToUser(ResultSet rs, int rowNum) throws SQLException { @@ -237,7 +238,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public void createUser(final UserDetails user) { validateUserDetails(user); - getJdbcTemplate().update(this.createUserSql, (ps) -> { + requireJdbcTemplate().update(this.createUserSql, (ps) -> { ps.setString(1, user.getUsername()); ps.setString(2, user.getPassword()); ps.setBoolean(3, user.isEnabled()); @@ -257,7 +258,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public void updateUser(final UserDetails user) { validateUserDetails(user); - getJdbcTemplate().update(this.updateUserSql, (ps) -> { + requireJdbcTemplate().update(this.updateUserSql, (ps) -> { ps.setString(1, user.getPassword()); ps.setBoolean(2, user.isEnabled()); int paramCount = ps.getParameterMetaData().getParameterCount(); @@ -281,7 +282,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa private void insertUserAuthorities(UserDetails user) { for (GrantedAuthority auth : user.getAuthorities()) { - getJdbcTemplate().update(this.createAuthoritySql, user.getUsername(), auth.getAuthority()); + requireJdbcTemplate().update(this.createAuthoritySql, user.getUsername(), auth.getAuthority()); } } @@ -290,12 +291,12 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa if (getEnableAuthorities()) { deleteUserAuthorities(username); } - getJdbcTemplate().update(this.deleteUserSql, username); + requireJdbcTemplate().update(this.deleteUserSql, username); this.userCache.removeUserFromCache(username); } private void deleteUserAuthorities(String username) { - getJdbcTemplate().update(this.deleteUserAuthoritiesSql, username); + requireJdbcTemplate().update(this.deleteUserAuthoritiesSql, username); } @Override @@ -318,7 +319,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa this.logger.debug("No authentication manager set. Password won't be re-checked."); } this.logger.debug("Changing password for user '" + username + "'"); - getJdbcTemplate().update(this.changePasswordSql, newPassword, username); + requireJdbcTemplate().update(this.changePasswordSql, newPassword, username); Authentication authentication = createNewAuthentication(currentUser, newPassword); SecurityContext context = this.securityContextHolderStrategy.createEmptyContext(); context.setAuthentication(authentication); @@ -336,7 +337,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public boolean userExists(String username) { - List users = getJdbcTemplate().queryForList(this.userExistsSql, String.class, username); + List users = requireJdbcTemplate().queryForList(this.userExistsSql, String.class, username); if (users.size() > 1) { throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1); @@ -346,13 +347,13 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public List findAllGroups() { - return getJdbcTemplate().queryForList(this.findAllGroupsSql, String.class); + return requireJdbcTemplate().queryForList(this.findAllGroupsSql, String.class); } @Override public List findUsersInGroup(String groupName) { Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().queryForList(this.findUsersInGroupSql, String.class, groupName); + return requireJdbcTemplate().queryForList(this.findUsersInGroupSql, String.class, groupName); } @Override @@ -361,11 +362,11 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.notNull(authorities, "authorities cannot be null"); this.logger.debug("Creating new group '" + groupName + "' with authorities " + AuthorityUtils.authorityListToSet(authorities)); - getJdbcTemplate().update(this.insertGroupSql, groupName); + requireJdbcTemplate().update(this.insertGroupSql, groupName); int groupId = findGroupId(groupName); for (GrantedAuthority a : authorities) { String authority = a.getAuthority(); - getJdbcTemplate().update(this.insertGroupAuthoritySql, (ps) -> { + requireJdbcTemplate().update(this.insertGroupAuthoritySql, (ps) -> { ps.setInt(1, groupId); ps.setString(2, authority); }); @@ -378,9 +379,9 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.hasText(groupName, "groupName should have text"); int id = findGroupId(groupName); PreparedStatementSetter groupIdPSS = (ps) -> ps.setInt(1, id); - getJdbcTemplate().update(this.deleteGroupMembersSql, groupIdPSS); - getJdbcTemplate().update(this.deleteGroupAuthoritiesSql, groupIdPSS); - getJdbcTemplate().update(this.deleteGroupSql, groupIdPSS); + requireJdbcTemplate().update(this.deleteGroupMembersSql, groupIdPSS); + requireJdbcTemplate().update(this.deleteGroupAuthoritiesSql, groupIdPSS); + requireJdbcTemplate().update(this.deleteGroupSql, groupIdPSS); } @Override @@ -388,7 +389,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa this.logger.debug("Changing group name from '" + oldName + "' to '" + newName + "'"); Assert.hasText(oldName, "oldName should have text"); Assert.hasText(newName, "newName should have text"); - getJdbcTemplate().update(this.renameGroupSql, newName, oldName); + requireJdbcTemplate().update(this.renameGroupSql, newName, oldName); } @Override @@ -397,7 +398,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.hasText(username, "username should have text"); Assert.hasText(groupName, "groupName should have text"); int id = findGroupId(groupName); - getJdbcTemplate().update(this.insertGroupMemberSql, (ps) -> { + requireJdbcTemplate().update(this.insertGroupMemberSql, (ps) -> { ps.setInt(1, id); ps.setString(2, username); }); @@ -410,7 +411,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.hasText(username, "username should have text"); Assert.hasText(groupName, "groupName should have text"); int id = findGroupId(groupName); - getJdbcTemplate().update(this.deleteGroupMemberSql, (ps) -> { + requireJdbcTemplate().update(this.deleteGroupMemberSql, (ps) -> { ps.setInt(1, id); ps.setString(2, username); }); @@ -421,7 +422,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa public List findGroupAuthorities(String groupName) { this.logger.debug("Loading authorities for group '" + groupName + "'"); Assert.hasText(groupName, "groupName should have text"); - return getJdbcTemplate().query(this.groupAuthoritiesSql, this.grantedAuthorityMapper, groupName); + return requireJdbcTemplate().query(this.groupAuthoritiesSql, this.grantedAuthorityMapper, groupName); } private GrantedAuthority mapToGrantedAuthority(ResultSet rs, int rowNum) throws SQLException { @@ -435,7 +436,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.hasText(groupName, "groupName should have text"); Assert.notNull(authority, "authority cannot be null"); int id = findGroupId(groupName); - getJdbcTemplate().update(this.deleteGroupAuthoritySql, (ps) -> { + requireJdbcTemplate().update(this.deleteGroupAuthoritySql, (ps) -> { ps.setInt(1, id); ps.setString(2, authority.getAuthority()); }); @@ -447,14 +448,20 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa Assert.hasText(groupName, "groupName should have text"); Assert.notNull(authority, "authority cannot be null"); int id = findGroupId(groupName); - getJdbcTemplate().update(this.insertGroupAuthoritySql, (ps) -> { + requireJdbcTemplate().update(this.insertGroupAuthoritySql, (ps) -> { ps.setInt(1, id); ps.setString(2, authority.getAuthority()); }); } private int findGroupId(String group) { - return getJdbcTemplate().queryForObject(this.findGroupIdSql, Integer.class, group); + return requireJdbcTemplate().queryForObject(this.findGroupIdSql, Integer.class, group); + } + + private JdbcTemplate requireJdbcTemplate() { + JdbcTemplate jdbc = getJdbcTemplate(); + Assert.notNull(jdbc, "JdbcTemplate cannot be null"); + return jdbc; } /** From a683a3a730209ab0a98448b5f2f469ada10f0c1a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:51:40 -0600 Subject: [PATCH 096/504] Favor PathPatternMessageMatcher when activated Issue gh-16500 --- .../MessageMatcherAuthorizationManagerConfiguration.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java index 0cb3259483..8977662092 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/socket/MessageMatcherAuthorizationManagerConfiguration.java @@ -31,6 +31,9 @@ final class MessageMatcherAuthorizationManagerConfiguration { MessageMatcherDelegatingAuthorizationManager.Builder messageAuthorizationManagerBuilder( ApplicationContext context) { MessageMatcherFactory.setApplicationContext(context); + if (MessageMatcherFactory.usesPathPatterns()) { + return MessageMatcherDelegatingAuthorizationManager.builder(); + } return MessageMatcherDelegatingAuthorizationManager.builder() .simpDestPathMatcher( () -> (context.getBeanNamesForType(SimpAnnotationMethodMessageHandler.class).length > 0) From 7d6bdfedc807fb4abff7da9307bb3f42425391f2 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 22 Apr 2025 15:40:11 -0600 Subject: [PATCH 097/504] Add Null Guard for Authorization Result --- .../registration/PublicKeyCredentialCreationOptionsFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java b/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java index 5a695a1f0b..414cd47883 100644 --- a/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java +++ b/web/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java @@ -105,7 +105,7 @@ public class PublicKeyCredentialCreationOptionsFilter extends OncePerRequestFilt Supplier context = this.securityContextHolderStrategy.getDeferredContext(); Supplier authentication = () -> context.get().getAuthentication(); AuthorizationResult result = this.authorization.authorize(authentication, request); - if (!result.isGranted()) { + if (result == null || !result.isGranted()) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return; } From 5c407483a0cad28a257164523dc78a90412c7f87 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:49:07 -0500 Subject: [PATCH 098/504] Create codeql.yml Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .github/workflows/codeql.yml | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..53edba63c6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,106 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main", "6.4.x", "6.3.x", "docs-build", "gh-pages" ] + pull_request: + branches: [ "main", "6.4.x", "6.3.x", "docs-build", "gh-pages" ] + schedule: + - cron: '15 2 * * 0' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: java-kotlin + build-mode: autobuild + - language: javascript-typescript + build-mode: none + - language: python + build-mode: none + - language: ruby + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 21b4763d1c37e3bb443ab39ff060be8d6ba3254e Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:56:22 -0500 Subject: [PATCH 099/504] Explicitly disable the default codeql setup Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 53edba63c6..8c1290c882 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -77,6 +77,7 @@ jobs: with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} + initialize: false # Explicitly disable the default setup # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. From 4a12382d2b480dd953a4ca4f84798dfef3b1d1c5 Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Mon, 14 Apr 2025 18:13:09 +0300 Subject: [PATCH 100/504] Remove unused classes Remove DeferringObservationAuthorizationManager.java and DeferringObservationReactiveAuthorizationManager.java Signed-off-by: Max Batischev --- ...erringObservationAuthorizationManager.java | 72 ------------------ ...servationReactiveAuthorizationManager.java | 73 ------------------- 2 files changed, 145 deletions(-) delete mode 100644 config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationAuthorizationManager.java delete mode 100644 config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationReactiveAuthorizationManager.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationAuthorizationManager.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationAuthorizationManager.java deleted file mode 100644 index 3328531606..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationAuthorizationManager.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.method.configuration; - -import java.util.function.Supplier; - -import io.micrometer.observation.ObservationRegistry; -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.authorization.AuthorizationResult; -import org.springframework.security.authorization.ObservationAuthorizationManager; -import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler; -import org.springframework.security.authorization.method.MethodInvocationResult; -import org.springframework.security.authorization.method.ThrowingMethodAuthorizationDeniedHandler; -import org.springframework.security.core.Authentication; -import org.springframework.util.function.SingletonSupplier; - -final class DeferringObservationAuthorizationManager - implements AuthorizationManager, MethodAuthorizationDeniedHandler { - - private final Supplier> delegate; - - private MethodAuthorizationDeniedHandler handler = new ThrowingMethodAuthorizationDeniedHandler(); - - DeferringObservationAuthorizationManager(ObjectProvider provider, - AuthorizationManager delegate) { - this.delegate = SingletonSupplier.of(() -> { - ObservationRegistry registry = provider.getIfAvailable(() -> ObservationRegistry.NOOP); - if (registry.isNoop()) { - return delegate; - } - return new ObservationAuthorizationManager<>(registry, delegate); - }); - if (delegate instanceof MethodAuthorizationDeniedHandler h) { - this.handler = h; - } - } - - @Override - public AuthorizationDecision check(Supplier authentication, T object) { - return this.delegate.get().check(authentication, object); - } - - @Override - public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) { - return this.handler.handleDeniedInvocation(methodInvocation, authorizationResult); - } - - @Override - public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult, - AuthorizationResult authorizationResult) { - return this.handler.handleDeniedInvocationResult(methodInvocationResult, authorizationResult); - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationReactiveAuthorizationManager.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationReactiveAuthorizationManager.java deleted file mode 100644 index 8b028a7077..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/DeferringObservationReactiveAuthorizationManager.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2002-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.method.configuration; - -import java.util.function.Supplier; - -import io.micrometer.observation.ObservationRegistry; -import org.aopalliance.intercept.MethodInvocation; -import reactor.core.publisher.Mono; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationResult; -import org.springframework.security.authorization.ObservationReactiveAuthorizationManager; -import org.springframework.security.authorization.ReactiveAuthorizationManager; -import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler; -import org.springframework.security.authorization.method.MethodInvocationResult; -import org.springframework.security.authorization.method.ThrowingMethodAuthorizationDeniedHandler; -import org.springframework.security.core.Authentication; -import org.springframework.util.function.SingletonSupplier; - -final class DeferringObservationReactiveAuthorizationManager - implements ReactiveAuthorizationManager, MethodAuthorizationDeniedHandler { - - private final Supplier> delegate; - - private MethodAuthorizationDeniedHandler handler = new ThrowingMethodAuthorizationDeniedHandler(); - - DeferringObservationReactiveAuthorizationManager(ObjectProvider provider, - ReactiveAuthorizationManager delegate) { - this.delegate = SingletonSupplier.of(() -> { - ObservationRegistry registry = provider.getIfAvailable(() -> ObservationRegistry.NOOP); - if (registry.isNoop()) { - return delegate; - } - return new ObservationReactiveAuthorizationManager<>(registry, delegate); - }); - if (delegate instanceof MethodAuthorizationDeniedHandler h) { - this.handler = h; - } - } - - @Override - public Mono check(Mono authentication, T object) { - return this.delegate.get().check(authentication, object); - } - - @Override - public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) { - return this.handler.handleDeniedInvocation(methodInvocation, authorizationResult); - } - - @Override - public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult, - AuthorizationResult authorizationResult) { - return this.handler.handleDeniedInvocationResult(methodInvocationResult, authorizationResult); - } - -} From 68ea952d5ad705cc182b5a2b28f0da7116e9a1b4 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:09:15 -0500 Subject: [PATCH 101/504] Update codeql.yml Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .github/workflows/codeql.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8c1290c882..4ab92e6213 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,11 +13,11 @@ name: "CodeQL Advanced" on: push: - branches: [ "main", "6.4.x", "6.3.x", "docs-build", "gh-pages" ] + branches: [ "main", "6.3.x", "6.4.x", "docs-build", "gh-pages" ] pull_request: - branches: [ "main", "6.4.x", "6.3.x", "docs-build", "gh-pages" ] + branches: [ "main", "6.3.x", "6.4.x", "docs-build", "gh-pages" ] schedule: - - cron: '15 2 * * 0' + - cron: '17 20 * * 3' jobs: analyze: @@ -77,7 +77,6 @@ jobs: with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} - initialize: false # Explicitly disable the default setup # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. From ce5a12b2f716366a13f9559371981e7251435443 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 18 Apr 2025 16:44:22 +0800 Subject: [PATCH 102/504] Revise document to replace outdated NimbusOpaqueTokenIntrospector with SpringOpaqueTokenIntrospector Signed-off-by: Yanming Zhou --- .../reactive/oauth2/resource-server/opaque-token.adoc | 5 ++--- .../servlet/oauth2/resource-server/opaque-token.adoc | 11 +++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc index 90524aa030..51aea50707 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc @@ -3,9 +3,8 @@ [[webflux-oauth2resourceserver-opaque-minimaldependencies]] == Minimal Dependencies for Introspection As described in xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-minimaldependencies[Minimal Dependencies for JWT], most Resource Server support is collected in `spring-security-oauth2-resource-server`. -However, unless you provide a custom <>, the Resource Server falls back to `ReactiveOpaqueTokenIntrospector`. -This means that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. -See `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`. +However, unless you provide a custom <>, the Resource Server falls back to `SpringReactiveOpaqueTokenIntrospector`. +This means that only `spring-security-oauth2-resource-server` is necessary to have a working minimal Resource Server that supports opaque Bearer Tokens. [[webflux-oauth2resourceserver-opaque-minimalconfiguration]] == Minimal Configuration for Introspection diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc index 2798fd2206..e547fd21c7 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc @@ -4,9 +4,8 @@ [[oauth2resourceserver-opaque-minimaldependencies]] == Minimal Dependencies for Introspection As described in xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-minimaldependencies[Minimal Dependencies for JWT] most of Resource Server support is collected in `spring-security-oauth2-resource-server`. -However unless a custom <> is provided, the Resource Server will fallback to NimbusOpaqueTokenIntrospector. -Meaning that both `spring-security-oauth2-resource-server` and `oauth2-oidc-sdk` are necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. -Please refer to `spring-security-oauth2-resource-server` in order to determine the correct version for `oauth2-oidc-sdk`. +However unless a custom <> is provided, the Resource Server will fallback to `SpringOpaqueTokenIntrospector`. +This means that only `spring-security-oauth2-resource-server` is necessary in order to have a working minimal Resource Server that supports opaque Bearer Tokens. [[oauth2resourceserver-opaque-minimalconfiguration]] == Minimal Configuration for Introspection @@ -361,7 +360,7 @@ Xml:: [source,xml,role="primary"] ---- + class="org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector"> @@ -445,7 +444,7 @@ Xml:: [source,xml,role="secondary"] ---- + class="org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector"> @@ -740,7 +739,7 @@ By default, Resource Server uses connection and socket timeouts of 30 seconds ea This may be too short in some scenarios. Further, it doesn't take into account more sophisticated patterns like back-off and discovery. -To adjust the way in which Resource Server connects to the authorization server, `NimbusOpaqueTokenIntrospector` accepts an instance of `RestOperations`: +To adjust the way in which Resource Server connects to the authorization server, `SpringOpaqueTokenIntrospector` accepts an instance of `RestOperations`: [tabs] ====== From f44ab7afdff535fa5e546b6f5546f61d126f3035 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:16:29 -0600 Subject: [PATCH 103/504] Update Deprecated Security Usage --- .../security/config/web/server/ServerHttpSecurity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index dd25029229..a6d77b3683 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -111,9 +111,9 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory; import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager; import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; -import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenAuthenticationConverter; import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; +import org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler; import org.springframework.security.oauth2.server.resource.web.server.BearerTokenServerAuthenticationEntryPoint; import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter; @@ -5443,7 +5443,7 @@ public class ServerHttpSecurity { public OpaqueTokenSpec introspectionUri(String introspectionUri) { Assert.hasText(introspectionUri, "introspectionUri cannot be empty"); this.introspectionUri = introspectionUri; - this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, + this.introspector = () -> new SpringReactiveOpaqueTokenIntrospector(this.introspectionUri, this.clientId, this.clientSecret); return this; } @@ -5459,7 +5459,7 @@ public class ServerHttpSecurity { Assert.notNull(clientSecret, "clientSecret cannot be null"); this.clientId = clientId; this.clientSecret = clientSecret; - this.introspector = () -> new NimbusReactiveOpaqueTokenIntrospector(this.introspectionUri, + this.introspector = () -> new SpringReactiveOpaqueTokenIntrospector(this.introspectionUri, this.clientId, this.clientSecret); return this; } From 8525f0e3fdeb1a27a78b20eeaa5fc5ec6a589a6b Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Thu, 17 Apr 2025 16:30:38 +0300 Subject: [PATCH 104/504] Add FunctionalInterface To X509PrincipalExtractor Closes gh-16949 Signed-off-by: Max Batischev --- .../authentication/preauth/x509/X509PrincipalExtractor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PrincipalExtractor.java index 7ecb2c95c3..3e33e79bb5 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PrincipalExtractor.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PrincipalExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.security.cert.X509Certificate; * * @author Luke Taylor */ +@FunctionalInterface public interface X509PrincipalExtractor { /** From 29380a87a00cf40696b727474ebb17c539b72874 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Fri, 11 Apr 2025 23:05:03 +0700 Subject: [PATCH 105/504] Polish javadoc Signed-off-by: Tran Ngoc Nhan --- .../util/matcher/PathPatternRequestMatcher.java | 6 ++++-- .../security/web/util/matcher/RequestMatcher.java | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java b/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java index c9c92c2b4b..86cc860e0f 100644 --- a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java +++ b/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java @@ -172,7 +172,9 @@ public final class PathPatternRequestMatcher implements RequestMatcher { * *

* If you have many paths that have a common path prefix, you can use - * {@link #basePath} to reduce repetition like so: + * {@link #basePath} to reduce repetition like so: + * + *

 	 *     PathPatternRequestMatcher.Builder mvc = withDefaults().basePath("/mvc");
 	 *     http
 	 *         .authorizeHttpRequests((authorize) -> authorize
@@ -180,7 +182,7 @@ public final class PathPatternRequestMatcher implements RequestMatcher {
 	 *              .requestMatchers(mvc.matcher("/admin/**")).hasAuthority("admin")
 	 *         )
 	 *             ...
-	 * 
+	 * 
*/ public static final class Builder { diff --git a/web/src/main/java/org/springframework/security/web/util/matcher/RequestMatcher.java b/web/src/main/java/org/springframework/security/web/util/matcher/RequestMatcher.java index e6b223d977..3f81ce156b 100644 --- a/web/src/main/java/org/springframework/security/web/util/matcher/RequestMatcher.java +++ b/web/src/main/java/org/springframework/security/web/util/matcher/RequestMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public interface RequestMatcher { boolean matches(HttpServletRequest request); /** - * Returns a MatchResult for this RequestMatcher The default implementation returns + * Returns a MatchResult for this RequestMatcher. The default implementation returns * {@link Collections#emptyMap()} when {@link MatchResult#getVariables()} is invoked. * @return the MatchResult from comparing this RequestMatcher against the * HttpServletRequest @@ -50,7 +50,7 @@ public interface RequestMatcher { } /** - * The result of matching against an HttpServletRequest Contains the status, true or + * The result of matching against an HttpServletRequest contains the status, true or * false, of the match and if present, any variables extracted from the match * * @since 5.2 @@ -86,7 +86,7 @@ public interface RequestMatcher { /** * Creates an instance of {@link MatchResult} that is a match with no variables - * @return + * @return {@link MatchResult} that is a match with no variables */ public static MatchResult match() { return new MatchResult(true, Collections.emptyMap()); @@ -95,8 +95,8 @@ public interface RequestMatcher { /** * Creates an instance of {@link MatchResult} that is a match with the specified * variables - * @param variables - * @return + * @param variables the specified variables + * @return {@link MatchResult} that is a match with the specified variables */ public static MatchResult match(Map variables) { return new MatchResult(true, variables); @@ -104,7 +104,7 @@ public interface RequestMatcher { /** * Creates an instance of {@link MatchResult} that is not a match. - * @return + * @return {@link MatchResult} that is not a match */ public static MatchResult notMatch() { return new MatchResult(false, Collections.emptyMap()); From 25e4b74cfaf94659f6f2aa312ba80c85a521e872 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:42:10 -0500 Subject: [PATCH 106/504] Delete .github/workflows/codeql.yml Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .github/workflows/codeql.yml | 106 ----------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 4ab92e6213..0000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,106 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL Advanced" - -on: - push: - branches: [ "main", "6.3.x", "6.4.x", "docs-build", "gh-pages" ] - pull_request: - branches: [ "main", "6.3.x", "6.4.x", "docs-build", "gh-pages" ] - schedule: - - cron: '17 20 * * 3' - -jobs: - analyze: - name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - permissions: - # required for all workflows - security-events: write - - # required to fetch internal or private CodeQL packs - packages: read - - # only required for workflows in private repositories - actions: read - contents: read - - strategy: - fail-fast: false - matrix: - include: - - language: actions - build-mode: none - - language: java-kotlin - build-mode: autobuild - - language: javascript-typescript - build-mode: none - - language: python - build-mode: none - - language: ruby - build-mode: none - # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Add any setup steps before running the `github/codeql-action/init` action. - # This includes steps like installing compilers or runtimes (`actions/setup-node` - # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" From 55de63447d66630a792e64793ce235b0aa47fd26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 03:26:39 +0000 Subject: [PATCH 107/504] Bump com.google.code.gson:gson from 2.13.0 to 2.13.1 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.13.0...gson-parent-2.13.1) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ad209324e7..1366352972 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -94,7 +94,7 @@ org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-lda org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" -com-google-code-gson-gson = "com.google.code.gson:gson:2.13.0" +com-google-code-gson-gson = "com.google.code.gson:gson:2.13.1" com-thaiopensource-trag = "com.thaiopensource:trang:20091111" net-sourceforge-saxon-saxon = "net.sourceforge.saxon:saxon:9.1.0.8" org-yaml-snakeyaml = "org.yaml:snakeyaml:1.33" From d2d1275b39b4adea988ad58b35ef57f3644c3817 Mon Sep 17 00:00:00 2001 From: Roman Trapickin <8594293+rntrp@users.noreply.github.com> Date: Mon, 21 Apr 2025 10:44:17 +0200 Subject: [PATCH 108/504] Fix IllegalArgumentException message for unknown Argon2 types Array index 0 points to an empty string. Use index 1 instead. Signed-off-by: Roman Trapickin <8594293+rntrp@users.noreply.github.com> --- .../security/crypto/argon2/Argon2EncodingUtils.java | 2 +- .../security/crypto/argon2/Argon2EncodingUtilsTests.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java b/crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java index 4b27d90318..9f06c8bb24 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java +++ b/crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java @@ -111,7 +111,7 @@ final class Argon2EncodingUtils { case "argon2d" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d); case "argon2i" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_i); case "argon2id" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id); - default -> throw new IllegalArgumentException("Invalid algorithm type: " + parts[0]); + default -> throw new IllegalArgumentException("Invalid algorithm type: " + parts[1]); }; if (parts[currentPart].startsWith("v=")) { paramsBuilder.withVersion(Integer.parseInt(parts[currentPart].substring(2))); diff --git a/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java b/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java index abae39532f..b4c0b9a3d0 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java @@ -95,7 +95,8 @@ public class Argon2EncodingUtilsTests { @Test public void decodeWhenNonexistingAlgorithmThenThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> Argon2EncodingUtils - .decode("$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs")); + .decode("$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs")) + .withMessageContaining("argon2x"); } @Test From 547d174f3edda42d001dfaf4e693247a3fb080a4 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:21:59 -0600 Subject: [PATCH 109/504] Fix Formatting --- .../security/crypto/argon2/Argon2EncodingUtilsTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java b/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java index b4c0b9a3d0..265527e71e 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2EncodingUtilsTests.java @@ -94,8 +94,9 @@ public class Argon2EncodingUtilsTests { @Test public void decodeWhenNonexistingAlgorithmThenThrowException() { - assertThatIllegalArgumentException().isThrownBy(() -> Argon2EncodingUtils - .decode("$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs")) + assertThatIllegalArgumentException() + .isThrownBy(() -> Argon2EncodingUtils.decode( + "$argon2x$v=19$m=1024,t=3,p=2$Y1JkRmJDdzIzZ3oyTWx4aw$cGE5Cbd/cx7micVhXVBdH5qTr66JI1iUyuNNVAnErXs")) .withMessageContaining("argon2x"); } From 226e81d7f55d38603f3f179d3e32caf3e7ed6a20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 03:34:18 +0000 Subject: [PATCH 110/504] Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.19.0 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.3 to 2.19.0. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.3...jackson-bom-2.19.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1366352972..96d16e0765 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "6.2.6" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.3" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 832572803543d1ec4436e1b9d780ad2a4b008362 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:16:44 -0500 Subject: [PATCH 111/504] rm merge-dependabot-pr.yml from Unsupported Branch --- .github/workflows/merge-dependabot-pr.yml | 63 ----------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/merge-dependabot-pr.yml diff --git a/.github/workflows/merge-dependabot-pr.yml b/.github/workflows/merge-dependabot-pr.yml deleted file mode 100644 index 4f2168eb3b..0000000000 --- a/.github/workflows/merge-dependabot-pr.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Merge Dependabot PR - -on: pull_request_target - -run-name: Merge Dependabot PR ${{ github.ref_name }} - -permissions: write-all - -jobs: - merge-dependabot-pr: - name: Merge Dependabot PR - runs-on: ubuntu-latest - if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }} - steps: - - - uses: actions/checkout@v4 - with: - show-progress: false - ref: ${{ github.event.pull_request.head.sha }} - - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - - - name: Set Milestone to Dependabot Pull Request - id: set-milestone - run: | - if test -f pom.xml - then - CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout) - else - CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }') - fi - export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT} - MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title') - - if [ -z $MILESTONE ] - then - gh run cancel ${{ github.run_id }} - echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version" - else - gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE - echo mergeEnabled=true >> $GITHUB_OUTPUT - fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Merge Dependabot pull request - if: steps.set-milestone.outputs.mergeEnabled - run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - send-notification: - name: Send Notification - needs: [ merge-dependabot-pr ] - if: ${{ failure() || cancelled() }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} From db48d4ca50e8c8afd2475ce2a6d737943822acca Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:17:14 -0500 Subject: [PATCH 112/504] rm merge-dependabot-pr.yml from Unsupported Branch --- .github/workflows/merge-dependabot-pr.yml | 63 ----------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/merge-dependabot-pr.yml diff --git a/.github/workflows/merge-dependabot-pr.yml b/.github/workflows/merge-dependabot-pr.yml deleted file mode 100644 index 4f2168eb3b..0000000000 --- a/.github/workflows/merge-dependabot-pr.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Merge Dependabot PR - -on: pull_request_target - -run-name: Merge Dependabot PR ${{ github.ref_name }} - -permissions: write-all - -jobs: - merge-dependabot-pr: - name: Merge Dependabot PR - runs-on: ubuntu-latest - if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }} - steps: - - - uses: actions/checkout@v4 - with: - show-progress: false - ref: ${{ github.event.pull_request.head.sha }} - - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - - - name: Set Milestone to Dependabot Pull Request - id: set-milestone - run: | - if test -f pom.xml - then - CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout) - else - CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }') - fi - export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT} - MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title') - - if [ -z $MILESTONE ] - then - gh run cancel ${{ github.run_id }} - echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version" - else - gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE - echo mergeEnabled=true >> $GITHUB_OUTPUT - fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Merge Dependabot pull request - if: steps.set-milestone.outputs.mergeEnabled - run: gh pr merge ${{ github.event.pull_request.number }} --auto --rebase - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - send-notification: - name: Send Notification - needs: [ merge-dependabot-pr ] - if: ${{ failure() || cancelled() }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} From 5354e4d2c56a96036914cbed6d1ae9eaf2a19273 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:18:32 -0600 Subject: [PATCH 113/504] Check for Null Issuer Closes gh-16989 --- .../OpenSaml4AuthenticationProvider.java | 13 ++++++++++--- .../OpenSaml4AuthenticationProviderTests.java | 11 ++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index 59f2585596..13987df902 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -391,7 +391,7 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv String inResponseTo = response.getInResponseTo(); result = result.concat(validateInResponseTo(token.getAuthenticationRequest(), inResponseTo)); - String issuer = response.getIssuer().getValue(); + String issuer = issuer(response); String destination = response.getDestination(); String location = token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation(); if (StringUtils.hasText(destination) && !destination.equals(location)) { @@ -414,6 +414,13 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv }; } + private static String issuer(Response response) { + if (response.getIssuer() == null) { + return null; + } + return response.getIssuer().getValue(); + } + private static List getStatusCodes(Response response) { if (response.getStatus() == null) { return List.of(StatusCode.SUCCESS); @@ -576,7 +583,7 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv } private void process(Saml2AuthenticationToken token, Response response) { - String issuer = response.getIssuer().getValue(); + String issuer = issuer(response); this.logger.debug(LogMessage.format("Processing SAML response from %s", issuer)); boolean responseSigned = response.isSigned(); diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java index abe4a4549a..bb3e61519b 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -861,6 +861,15 @@ public class OpenSaml4AuthenticationProviderTests { provider.authenticate(token); } + // gh-16989 + @Test + public void authenticateWhenNullIssuerThenNoNullPointer() { + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + Response response = TestOpenSamlObjects.signedResponseWithOneAssertion((r) -> r.setIssuer(null)); + Saml2AuthenticationToken token = token(response, verifying(registration())); + assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token)); + } + private T build(QName qName) { return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName); } From 868342b3a91709afacde3e03c53a4d79ed612851 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:25:31 -0600 Subject: [PATCH 114/504] Add OpenSAML 5 Test Issue gh-17008 --- .../OpenSaml5AuthenticationProviderTests.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index 284c7a90c3..07e4ad90e4 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -889,6 +889,15 @@ public class OpenSaml5AuthenticationProviderTests { provider.authenticate(token); } + // gh-16989 + @Test + public void authenticateWhenNullIssuerThenNoNullPointer() { + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + Response response = TestOpenSamlObjects.signedResponseWithOneAssertion((r) -> r.setIssuer(null)); + Saml2AuthenticationToken token = token(response, verifying(registration())); + assertThatExceptionOfType(Saml2AuthenticationException.class).isThrownBy(() -> provider.authenticate(token)); + } + private T build(QName qName) { return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName); } From c855453e40c7bef714a0a713311cc4bb208527db Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 25 Apr 2025 17:00:30 +0300 Subject: [PATCH 115/504] Fix Typo In SubjectDnX509PrincipalExtractorTests Signed-off-by: Max Batischev --- .../preauth/x509/SubjectDnX509PrincipalExtractorTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractorTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractorTests.java index a86b41e0bc..73e179d5c9 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractorTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,7 +49,7 @@ public class SubjectDnX509PrincipalExtractorTests { } @Test - public void defaultCNPatternReturnsExcpectedPrincipal() throws Exception { + public void defaultCNPatternReturnsExpectedPrincipal() throws Exception { Object principal = this.extractor.extractPrincipal(X509TestUtils.buildTestCertificate()); assertThat(principal).isEqualTo("Luke Taylor"); } From 9c76ab69f051c832e2bcf02db50c8a0e7598a853 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Mon, 28 Apr 2025 10:01:23 +0800 Subject: [PATCH 116/504] Use proper configuration key the getter method is `getOpaquetoken()` not `getOpaqueToken()` See https://github.com/spring-projects/spring-boot/blob/c6045c3111c43bd7b0f99e6c2858bfb2999e358f/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java#L51 Signed-off-by: Yanming Zhou --- .../pages/reactive/oauth2/resource-server/opaque-token.adoc | 4 ++-- .../pages/servlet/oauth2/resource-server/opaque-token.adoc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc index 8cab012346..0ec61ddb78 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc @@ -29,7 +29,7 @@ spring: security: oauth2: resourceserver: - opaque-token: + opaquetoken: introspection-uri: https://idp.example.com/introspect client-id: client client-secret: secret @@ -616,7 +616,7 @@ spring: security: oauth2: resourceserver: - opaque-token: + opaquetoken: introspection-uri: https://idp.example.org/introspection client-id: client client-secret: secret diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc index 82968028a7..954a35127e 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc @@ -28,7 +28,7 @@ spring: security: oauth2: resourceserver: - opaque-token: + opaquetoken: introspection-uri: https://idp.example.com/introspect client-id: client client-secret: secret @@ -782,7 +782,7 @@ spring: security: oauth2: resourceserver: - opaque-token: + opaquetoken: introspection-uri: https://idp.example.org/introspection client-id: client client-secret: secret From 0e84f31a001810af314cc25eb0c421cd37f96bd4 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Thu, 24 Apr 2025 20:12:45 +0300 Subject: [PATCH 117/504] Add ClientRegistration's RestClient failed attempts information to exception message Closes gh-16860 Signed-off-by: Evgeniy Cheban --- .../registration/ClientRegistrations.java | 9 +++++- .../ClientRegistrationsTests.java | 29 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java index 7fb2b889f7..1f698416d0 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.client.registration; import java.net.URI; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -49,6 +50,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Rob Winch * @author Josh Cummings * @author Rafiullah Hamedy + * @author Evgeniy Cheban * @since 5.1 */ public final class ClientRegistrations { @@ -211,6 +213,7 @@ public final class ClientRegistrations { private static ClientRegistration.Builder getBuilder(String issuer, Supplier... suppliers) { String errorMessage = "Unable to resolve Configuration with the provided Issuer of \"" + issuer + "\""; + List errors = new ArrayList<>(); for (Supplier supplier : suppliers) { try { return supplier.get(); @@ -219,6 +222,7 @@ public final class ClientRegistrations { if (!ex.getStatusCode().is4xxClientError()) { throw ex; } + errors.add(ex.getMessage()); // else try another endpoint } catch (IllegalArgumentException | IllegalStateException ex) { @@ -228,6 +232,9 @@ public final class ClientRegistrations { throw new IllegalArgumentException(errorMessage, ex); } } + if (!errors.isEmpty()) { + throw new IllegalArgumentException(errorMessage + ", errors: " + errors); + } throw new IllegalArgumentException(errorMessage); } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java index b3b74e805d..62954a2599 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,12 +36,14 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** * @author Rob Winch * @author Rafiullah Hamedy + * @author Evgeniy Cheban * @since 5.1 */ public class ClientRegistrationsTests { @@ -455,6 +457,31 @@ public class ClientRegistrationsTests { // @formatter:on } + @Test + public void issuerWhenAllEndpointsFailedThenExceptionIncludesFailureInformation() { + this.issuer = createIssuerFromServer("issuer1"); + this.server.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest request) { + int responseCode = switch (request.getPath()) { + case "/issuer1/.well-known/openid-configuration" -> 405; + case "/.well-known/openid-configuration/issuer1" -> 400; + default -> 404; + }; + return new MockResponse().setResponseCode(responseCode); + } + }); + String message = """ + Unable to resolve Configuration with the provided Issuer of "%s", errors: [\ + 405 Client Error: [no body], \ + 400 Client Error: [no body], \ + 404 Client Error: [no body]]\ + """.formatted(this.issuer); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer).build()) + .withMessage(message); + } + private ClientRegistration.Builder registration(String path) throws Exception { this.issuer = createIssuerFromServer(path); this.response.put("issuer", this.issuer); From f631a0fcd548418730b45ba48b7e82bf19cda8bd Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 29 Apr 2025 14:02:46 -0600 Subject: [PATCH 118/504] Polish ClientRegistrationsTests Simplified the assertion so that it is focused on the core behavior being verified. This will likely also make the test more stable when updating Spring Framework versions. Issue gh-16860 --- .../client/registration/ClientRegistrationsTests.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java index 62954a2599..7e59d2595b 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java @@ -471,15 +471,11 @@ public class ClientRegistrationsTests { return new MockResponse().setResponseCode(responseCode); } }); - String message = """ - Unable to resolve Configuration with the provided Issuer of "%s", errors: [\ - 405 Client Error: [no body], \ - 400 Client Error: [no body], \ - 404 Client Error: [no body]]\ - """.formatted(this.issuer); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer).build()) - .withMessage(message); + .withMessageContaining("405") + .withMessageContaining("400") + .withMessageContaining("404"); } private ClientRegistration.Builder registration(String path) throws Exception { From c8581683da5491ce5181b9f75beab539df3f9893 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 02:34:58 +0000 Subject: [PATCH 119/504] Bump Gradle Wrapper from 8.13 to 8.14. Release notes of Gradle 8.14 can be found here: https://docs.gradle.org/8.14/release-notes.html Signed-off-by: github-actions[bot] --- gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 4 ++-- gradlew.bat | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c742b298b441bfb90dbc124400a3751b9..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 642 zcmdmamFde>rVZJA^}0Q$xegf!xPEW^+5YDM%iT2bEgct9o+jH~+sJas#HZ=szO|** z=Pj=X_vx?W&DSwKck|WWn~hffsvnQ+42*W$b7b0$SCcOoZ`{W{^$^pk;4>8-A*-)$ z?n(Po`1$6Jn_u?t-L+tsPyZ2#X}8T6OS8pAU;kdgd+_Hw4z4TW0p9E!T+=f7-c&O% zFic^X{7^$?^Ho04eona9n#mGMxKhA=~8B%JN`M zMhm5wc-2v)$``sY$!Q`9xiU@DhI73ZxiGEKg>yIPs)NmWwMdF-ngLXpZSqV5ez36n zVkxF2rjrjWR+_xr6e6@_u@s~2uv{9vi*1pj2)BjFD+-%@&pRVP1f{O1glxTOp2-62Ph;v z`N1+vCd)9ea)af*Ol1*JCfnp$%Uu}%OuoN7g2}3C@`L5FlP#(sA=|h@iixuZC?qp^ z=L$=v$ZoI}|87Wh=&h7udff{aieKr*l+zDp?pf)_bbRvUf>kn;HCDMXNlgbbo!QRK I1x7am0No)LiU0rr delta 584 zcmexzm1*ZyrVZJAexH5Moc8h7)w{^+t*dqJ%=yhh23L$9JpFV=_k`zJ-?Q4DI*eSe z+ES)HSrVnWLtJ&)lO%hRkV9zl5qqWRt0e;bb zPPo`)y?HTAyZI&u&X<|2$FDHCf4;!v8}p=?Tm`^F0`u(|1ttf~&t$qP3KUSD>@TJQ zRwJ}Pim6NzEc8KA6)e;S6gs8=7IIL8sQL*MYEuRYO;Uj<%3UbMbV&^&!Zvx+LKmjT z8Zch6rYP7Tw?$Hn(UTJwWiS=$f{lB(C=e*%usDV})0AQIK~sat=ND@+Gg*Pyij!rR z*fa02W|%BsV++>4W{DKDGSIUEHd2$P+8ct!RF+CHDowUuTEZOZ%rJSQv*qOXOSPDN zT|sP-$p*_3ncsWB*qoD7JQcyZ9xan%cJP6Tb4-?AZpr*F6v98hoNaPJm@HV`yya5N z))6pqFXn@}P(3T0nEzM8*c_9KtE9o|_pFd&K35GBXP^9Kg(b6GH-z8S4GDzIl~T+b zdLd#meKKHu$5u))8cu$=GKINkGDPOUD)!0$C(BH(U!}!-e;Q0ok8Sc?V1zRO04>ts AA^-pY diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 36e4933e1d..247cf2a9f5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionSha256Sum=61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf93008b7..23d15a9367 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c79..5eed7ee845 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 1a4602c8c3a625c905e0e469ae19c2aa89869b39 Mon Sep 17 00:00:00 2001 From: hammadirshad Date: Sun, 23 Mar 2025 14:34:01 +0100 Subject: [PATCH 120/504] Add mapping for DPoP in DefaultMapOAuth2AccessTokenResponseConverter Closes gh-16806 Signed-off-by: muha --- ...faultMapOAuth2AccessTokenResponseConverter.java | 6 +++++- ...MapOAuth2AccessTokenResponseConverterTests.java | 14 +++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverter.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverter.java index 1e2220c48f..d8fea3d686 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverter.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,6 +70,10 @@ public final class DefaultMapOAuth2AccessTokenResponseConverter .equalsIgnoreCase(getParameterValue(tokenResponseParameters, OAuth2ParameterNames.TOKEN_TYPE))) { return OAuth2AccessToken.TokenType.BEARER; } + else if (OAuth2AccessToken.TokenType.DPOP.getValue() + .equalsIgnoreCase(getParameterValue(tokenResponseParameters, OAuth2ParameterNames.TOKEN_TYPE))) { + return OAuth2AccessToken.TokenType.DPOP; + } return null; } diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverterTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverterTests.java index 0b7433ffc0..44534b4e4e 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverterTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/DefaultMapOAuth2AccessTokenResponseConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -98,6 +98,18 @@ public class DefaultMapOAuth2AccessTokenResponseConverterTests { assertThat(additionalParameters).isEmpty(); } + @Test + public void shouldConvertDPoPToken() { + Map map = new HashMap<>(); + map.put("access_token", "access-token-1234"); + map.put("token_type", "dpop"); + OAuth2AccessTokenResponse converted = this.messageConverter.convert(map); + OAuth2AccessToken accessToken = converted.getAccessToken(); + assertThat(accessToken).isNotNull(); + assertThat(accessToken.getTokenValue()).isEqualTo("access-token-1234"); + assertThat(accessToken.getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.DPOP); + } + @Test public void shouldConvertWithUnsupportedExpiresIn() { Map map = new HashMap<>(); From 71421c68baee842f22ecb6977a243c7d097edb32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 04:05:35 +0000 Subject: [PATCH 121/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.29.0.RELEASE to 0.29.1.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.29.0.RELEASE...0.29.1.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-version: 0.29.1.RELEASE dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96d16e0765..5a28bec55b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.0.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.1.RELEASE' [plugins] From 742265375dbf8fd50c4ca2317ba208cb63689d4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 03:55:23 +0000 Subject: [PATCH 122/504] Bump io.mockk:mockk from 1.14.0 to 1.14.2 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.0 to 1.14.2. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.0...1.14.2) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a28bec55b..f780f9621e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" -io-mockk = "io.mockk:mockk:1.14.0" +io-mockk = "io.mockk:mockk:1.14.2" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From bcef6ed74f3d7a5459380cf25cc3c2adb1b425b9 Mon Sep 17 00:00:00 2001 From: Soumik Sarker Date: Tue, 29 Apr 2025 03:17:14 +0600 Subject: [PATCH 123/504] Reformatted lines in x509 overview documentation Signed-off-by: Soumik Sarker --- docs/modules/ROOT/pages/servlet/authentication/x509.adoc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/authentication/x509.adoc b/docs/modules/ROOT/pages/servlet/authentication/x509.adoc index 7180e1eef5..26dbb1a900 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/x509.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/x509.adoc @@ -8,14 +8,12 @@ The browser automatically checks that the certificate presented by a server has You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake. The server authenticates the client by checking that its certificate is signed by an acceptable authority. If a valid certificate has been provided, it can be obtained through the servlet API in an application. -The Spring Security X.509 module extracts the certificate by using a filter. -It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. - -You can also use SSL with "`mutual authentication`". The server then requests a valid certificate from the client as part of the SSL handshake. -The server authenticates the client by checking that its certificate is signed by an acceptable authority. For example, if you use Tomcat, you should read the https://tomcat.apache.org/tomcat-10.1-doc/ssl-howto.html[Tomcat SSL instructions]. You should get this working before trying it out with Spring Security. +The Spring Security X.509 module extracts the certificate by using a filter. +It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. + == Adding X.509 Authentication to Your Web Application Enabling X.509 client authentication is very straightforward. From ae09f3629140d7edb11969b5f8ed075472d4a556 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 11:15:37 -0500 Subject: [PATCH 124/504] Add .github/workflows/codeql.yml --- .github/workflows/codeql.yml | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..37f1db9de4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,80 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: # run if we update the workflow + workflow_dispatch: + schedule: + - cron: '39 13 * * 4' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: [self-hosted, Linux, X64, tpe-small-vm] + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + queries: security-extended,security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 1564076276e0711e48a93216a951a0fb0bf708e9 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 11:23:01 -0500 Subject: [PATCH 125/504] Remove automerge forward --- .../dependabot-auto-merge-forward.yml | 57 ------------------- .../trigger-dependabot-auto-merge-forward.yml | 22 ------- 2 files changed, 79 deletions(-) delete mode 100644 .github/workflows/dependabot-auto-merge-forward.yml delete mode 100644 .github/workflows/trigger-dependabot-auto-merge-forward.yml diff --git a/.github/workflows/dependabot-auto-merge-forward.yml b/.github/workflows/dependabot-auto-merge-forward.yml deleted file mode 100644 index 4989c57aa1..0000000000 --- a/.github/workflows/dependabot-auto-merge-forward.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Auto Merge Forward Dependabot Commits - -on: - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: dependabot-auto-merge-forward - -jobs: - get-supported-branches: - uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1 - with: - project: spring-security - type: oss - repository_name: spring-projects/spring-security - - auto-merge-forward-dependabot: - name: Auto Merge Forward Dependabot Commits - runs-on: ubuntu-latest - needs: [get-supported-branches] - permissions: - contents: write - steps: - - name: Checkout - id: checkout - uses: actions/checkout@v4 - with: - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - - name: Setup GitHub User - id: setup-gh-user - run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - - name: Run Auto Merge Forward - id: run-auto-merge-forward - uses: spring-io/spring-security-release-tools/.github/actions/auto-merge-forward@actions-v1 - with: - branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main - from-author: dependabot[bot] - notify_result: - name: Check for failures - needs: [ auto-merge-forward-dependabot ] - if: failure() - runs-on: ubuntu-latest - permissions: - actions: read - steps: - - name: Send Slack message - uses: Gamesight/slack-workflow-status@v1.3.0 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - channel: '#spring-security-ci' - name: 'CI Notifier' diff --git a/.github/workflows/trigger-dependabot-auto-merge-forward.yml b/.github/workflows/trigger-dependabot-auto-merge-forward.yml deleted file mode 100644 index 9bbb2ccbd5..0000000000 --- a/.github/workflows/trigger-dependabot-auto-merge-forward.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Trigger Dependabot Auto Merge Forward - -on: - push: - branches: - - '*.x' - -permissions: read-all - -jobs: - trigger-worflow: - name: Trigger Workflow - runs-on: ubuntu-latest - if: ${{ github.event.commits[0].author.username == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }} - steps: - - name: Checkout - id: checkout - uses: actions/checkout@v4 - - id: trigger - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: gh workflow run dependabot-auto-merge-forward.yml -r main From a04025c1148c7fd00401b3d33cb2d11877b64ad1 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 11:26:41 -0500 Subject: [PATCH 126/504] rm mark-duplicate-dependabot-prs.yml --- .../mark-duplicate-dependabot-prs.yml | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 .github/workflows/mark-duplicate-dependabot-prs.yml diff --git a/.github/workflows/mark-duplicate-dependabot-prs.yml b/.github/workflows/mark-duplicate-dependabot-prs.yml deleted file mode 100644 index 478e2ad814..0000000000 --- a/.github/workflows/mark-duplicate-dependabot-prs.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Mark Duplicate Dependabot PRs - -on: - pull_request: - types: [closed] - -jobs: - check_duplicate_prs: - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'dependabot[bot]' - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Extract Dependency Name from PR Title - id: extract - run: | - PR_TITLE="${{ github.event.pull_request.title }}" - DEPENDENCY_NAME=$(echo "$PR_TITLE" | awk -F ' from ' '{print $1}') - echo "dependency_name=$DEPENDENCY_NAME" >> $GITHUB_OUTPUT - - - name: Find PRs - id: find_duplicates - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PRS=$(gh pr list --search 'milestone:${{ github.event.pull_request.milestone.title }} is:merged in:title "${{ steps.extract.outputs.dependency_name }}"' --json number --jq 'map(.number) | join(",")') - echo "prs=$PRS" >> $GITHUB_OUTPUT - - - name: Label Duplicate PRs - if: steps.find_duplicates.outputs.prs != '' - env: - PRS: ${{ steps.find_duplicates.outputs.prs }} - CURRENT_PR_NUMBER: ${{ github.event.pull_request.number }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - for i in ${PRS//,/ } - do - if [ ! $i -eq "$CURRENT_PR_NUMBER" ]; then - echo "Marking PR $i as duplicate" - gh pr edit "$i" --add-label "status: duplicate" - gh pr comment "$i" --body "Duplicate of #$CURRENT_PR_NUMBER" - fi - done From 3b7e3a6c5ca62bc5154d03b2650f2281248e50e6 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 11:49:41 -0500 Subject: [PATCH 127/504] codeql uses ubuntu-latest --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 37f1db9de4..4c98186dd3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,7 +25,7 @@ jobs: # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: [self-hosted, Linux, X64, tpe-small-vm] + runs-on: ubuntu-latest permissions: # required for all workflows security-events: write From e48f26e51e9abbe54defb838c894d47cc92e7068 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 30 Apr 2025 17:11:50 -0600 Subject: [PATCH 128/504] Propagate StrictFirewallRequest Wrapper Closes gh-16978 --- .../StrictServerWebExchangeFirewall.java | 18 +++++++++--------- .../StrictServerWebExchangeFirewallTests.java | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java b/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java index 0916f1ffd9..72871f2b45 100644 --- a/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java +++ b/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -802,42 +802,42 @@ public class StrictServerWebExchangeFirewall implements ServerWebExchangeFirewal @Override public Builder method(HttpMethod httpMethod) { - return this.delegate.method(httpMethod); + return new StrictFirewallBuilder(this.delegate.method(httpMethod)); } @Override public Builder uri(URI uri) { - return this.delegate.uri(uri); + return new StrictFirewallBuilder(this.delegate.uri(uri)); } @Override public Builder path(String path) { - return this.delegate.path(path); + return new StrictFirewallBuilder(this.delegate.path(path)); } @Override public Builder contextPath(String contextPath) { - return this.delegate.contextPath(contextPath); + return new StrictFirewallBuilder(this.delegate.contextPath(contextPath)); } @Override public Builder header(String headerName, String... headerValues) { - return this.delegate.header(headerName, headerValues); + return new StrictFirewallBuilder(this.delegate.header(headerName, headerValues)); } @Override public Builder headers(Consumer headersConsumer) { - return this.delegate.headers(headersConsumer); + return new StrictFirewallBuilder(this.delegate.headers(headersConsumer)); } @Override public Builder sslInfo(SslInfo sslInfo) { - return this.delegate.sslInfo(sslInfo); + return new StrictFirewallBuilder(this.delegate.sslInfo(sslInfo)); } @Override public Builder remoteAddress(InetSocketAddress remoteAddress) { - return this.delegate.remoteAddress(remoteAddress); + return new StrictFirewallBuilder(this.delegate.remoteAddress(remoteAddress)); } @Override diff --git a/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java b/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java index b8803bc0d1..8f24b0522c 100644 --- a/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java +++ b/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -534,4 +534,17 @@ class StrictServerWebExchangeFirewallTests { .isThrownBy(() -> headers.get(invalidHeaderName)); } + // gh-16978 + @Test + void getMutatedFirewalledExchangeHeadersGetHeaderWhenNotAllowedHeaderNameThenException() { + String invalidHeaderName = "bad name"; + this.firewall.setAllowedHeaderNames((name) -> !name.equals(invalidHeaderName)); + ServerWebExchange exchange = getFirewalledExchange(); + var mutatedRequest = exchange.getRequest().mutate().method(HttpMethod.POST).build(); + var mutatedExchange = exchange.mutate().request(mutatedRequest).build(); + HttpHeaders headers = mutatedExchange.getRequest().getHeaders(); + assertThatExceptionOfType(ServerExchangeRejectedException.class) + .isThrownBy(() -> headers.get(invalidHeaderName)); + } + } From 1a6915d3c0386d51d988ef6a457c471e43443b57 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 12:35:31 -0500 Subject: [PATCH 129/504] rm .github/workflows for unsupported branch --- .github/workflows/clean_build_artifacts.yml | 23 ---- .../continuous-integration-workflow.yml | 125 ------------------ .github/workflows/deploy-docs.yml | 33 ----- .../gradle-wrapper-upgrade-execution.yml | 32 ----- .../mark-duplicate-dependabot-prs.yml | 45 ------- .../milestone-spring-releasetrain.yml | 35 ----- .github/workflows/pr-build-workflow.yml | 54 -------- .github/workflows/release-scheduler.yml | 24 ---- .../trigger-dependabot-auto-merge-forward.yml | 22 --- .../update-scheduled-release-version.yml | 23 ---- 10 files changed, 416 deletions(-) delete mode 100644 .github/workflows/clean_build_artifacts.yml delete mode 100644 .github/workflows/continuous-integration-workflow.yml delete mode 100644 .github/workflows/deploy-docs.yml delete mode 100644 .github/workflows/gradle-wrapper-upgrade-execution.yml delete mode 100644 .github/workflows/mark-duplicate-dependabot-prs.yml delete mode 100644 .github/workflows/milestone-spring-releasetrain.yml delete mode 100644 .github/workflows/pr-build-workflow.yml delete mode 100644 .github/workflows/release-scheduler.yml delete mode 100644 .github/workflows/trigger-dependabot-auto-merge-forward.yml delete mode 100644 .github/workflows/update-scheduled-release-version.yml diff --git a/.github/workflows/clean_build_artifacts.yml b/.github/workflows/clean_build_artifacts.yml deleted file mode 100644 index c116fac71d..0000000000 --- a/.github/workflows/clean_build_artifacts.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Clean build artifacts -on: - schedule: - - cron: '0 10 * * *' # Once per day at 10am UTC - -permissions: - contents: read - -jobs: - main: - runs-on: ubuntu-latest - if: ${{ github.repository == 'spring-projects/spring-security' }} - permissions: - contents: none - steps: - - name: Delete artifacts in cron job - env: - GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: | - echo "Running clean build artifacts logic" - output=$(curl -X GET -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts | grep '"id"' | cut -d : -f2 | sed 's/,*$//g') - echo Output is $output - for id in $output; do curl -X DELETE -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts/$id; done; diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml deleted file mode 100644 index cff9af47f3..0000000000 --- a/.github/workflows/continuous-integration-workflow.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: CI - -on: - push: - branches-ignore: - - "dependabot/**" - schedule: - - cron: '0 10 * * *' # Once per day at 10am UTC - workflow_dispatch: # Manual trigger - -env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - -permissions: - contents: read - -jobs: - build: - name: Build - uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@v1 - strategy: - matrix: - os: [ ubuntu-latest, windows-latest ] - jdk: [ 17 ] - with: - runs-on: ${{ matrix.os }} - java-version: ${{ matrix.jdk }} - distribution: temurin - secrets: inherit - test: - name: Test Against Snapshots - uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@v1 - strategy: - matrix: - include: - - java-version: 21-ea - toolchain: 21 - - java-version: 17 - toolchain: 17 - with: - java-version: ${{ matrix.java-version }} - test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.1.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2023.1.+ --stacktrace - secrets: inherit - check-samples: - name: Check Samples - runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'spring-projects' }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: 17 - distribution: temurin - - name: Check samples project - env: - LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos - SAMPLES_DIR: ../spring-security-samples - run: | - # Extract version from gradle.properties - version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}') - # Extract samplesBranch from gradle.properties - samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}') - ./gradlew publishMavenJavaPublicationToLocalRepository - ./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR" - ./gradlew --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" :runAllTests - check-tangles: - name: Check for Package Tangles - runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'spring-projects' }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: 17 - distribution: temurin - - name: Check for package tangles - env: - STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }} - run: | - ./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace - deploy-artifacts: - name: Deploy Artifacts - needs: [ build, test, check-samples, check-tangles ] - uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1 - with: - should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }} - secrets: inherit - deploy-docs: - name: Deploy Docs - needs: [ build, test, check-samples, check-tangles ] - uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1 - with: - should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }} - secrets: inherit - deploy-schema: - name: Deploy Schema - needs: [ build, test, check-samples, check-tangles ] - uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1 - with: - should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }} - secrets: inherit - perform-release: - name: Perform Release - needs: [ deploy-artifacts, deploy-docs, deploy-schema ] - uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1 - with: - should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }} - project-version: ${{ needs.deploy-artifacts.outputs.project-version }} - milestone-repo-url: https://repo.spring.io/artifactory/milestone - release-repo-url: https://repo1.maven.org/maven2 - artifact-path: org/springframework/security/spring-security-core - slack-announcing-id: spring-security-announcing - secrets: inherit - send-notification: - name: Send Notification - needs: [ perform-release ] - if: ${{ failure() || cancelled() }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml deleted file mode 100644 index 25381d0f82..0000000000 --- a/.github/workflows/deploy-docs.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Deploy Docs -on: - push: - branches-ignore: - - "gh-pages" - - "dependabot/**" - tags: '**' - repository_dispatch: - types: request-build-reference # legacy - #schedule: - #- cron: '0 10 * * *' # Once per day at 10am UTC - workflow_dispatch: -permissions: read-all -jobs: - build: - runs-on: ubuntu-latest - if: github.repository_owner == 'spring-projects' - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: docs-build - fetch-depth: 1 - - name: Dispatch (partial build) - if: github.ref_type == 'branch' - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }} - - name: Dispatch (full build) - if: github.ref_type == 'tag' - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) diff --git a/.github/workflows/gradle-wrapper-upgrade-execution.yml b/.github/workflows/gradle-wrapper-upgrade-execution.yml deleted file mode 100644 index 2cbc750d89..0000000000 --- a/.github/workflows/gradle-wrapper-upgrade-execution.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Execute Gradle Wrapper Upgrade - -on: - schedule: - - cron: '0 2 * * *' # 2am UTC - workflow_dispatch: - -jobs: - upgrade_wrapper: - name: Execution - runs-on: ubuntu-latest - steps: - - name: Set up Git configuration - env: - TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config --global url."https://unused-username:${TOKEN}@github.com/".insteadOf "https://github.com/" - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - - name: Checkout - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - - name: Set up Gradle - uses: gradle/gradle-build-action@v2 - - name: Upgrade Wrappers - run: ./gradlew clean upgradeGradleWrapperAll --continue -Porg.gradle.java.installations.auto-download=false - env: - WRAPPER_UPGRADE_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/mark-duplicate-dependabot-prs.yml b/.github/workflows/mark-duplicate-dependabot-prs.yml deleted file mode 100644 index 478e2ad814..0000000000 --- a/.github/workflows/mark-duplicate-dependabot-prs.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Mark Duplicate Dependabot PRs - -on: - pull_request: - types: [closed] - -jobs: - check_duplicate_prs: - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true && github.event.pull_request.user.login == 'dependabot[bot]' - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Extract Dependency Name from PR Title - id: extract - run: | - PR_TITLE="${{ github.event.pull_request.title }}" - DEPENDENCY_NAME=$(echo "$PR_TITLE" | awk -F ' from ' '{print $1}') - echo "dependency_name=$DEPENDENCY_NAME" >> $GITHUB_OUTPUT - - - name: Find PRs - id: find_duplicates - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PRS=$(gh pr list --search 'milestone:${{ github.event.pull_request.milestone.title }} is:merged in:title "${{ steps.extract.outputs.dependency_name }}"' --json number --jq 'map(.number) | join(",")') - echo "prs=$PRS" >> $GITHUB_OUTPUT - - - name: Label Duplicate PRs - if: steps.find_duplicates.outputs.prs != '' - env: - PRS: ${{ steps.find_duplicates.outputs.prs }} - CURRENT_PR_NUMBER: ${{ github.event.pull_request.number }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - for i in ${PRS//,/ } - do - if [ ! $i -eq "$CURRENT_PR_NUMBER" ]; then - echo "Marking PR $i as duplicate" - gh pr edit "$i" --add-label "status: duplicate" - gh pr comment "$i" --body "Duplicate of #$CURRENT_PR_NUMBER" - fi - done diff --git a/.github/workflows/milestone-spring-releasetrain.yml b/.github/workflows/milestone-spring-releasetrain.yml deleted file mode 100644 index 0602ae8e73..0000000000 --- a/.github/workflows/milestone-spring-releasetrain.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Check Milestone -on: - milestone: - types: [created, opened, edited] -env: - DUE_ON: ${{ github.event.milestone.due_on }} - TITLE: ${{ github.event.milestone.title }} -permissions: - contents: read -jobs: - spring-releasetrain-checks: - name: Check DueOn is on a Release Date - runs-on: ubuntu-latest - if: ${{ github.repository == 'spring-projects/spring-security' }} - permissions: - contents: none - steps: - - name: Print Milestone Being Checked - run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'" - - name: Validate DueOn - if: env.DUE_ON != '' - run: | - export TOOL_VERSION=0.1.1 - wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar" - java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3 - send-notification: - name: Send Notification - needs: [ spring-releasetrain-checks ] - if: ${{ failure() || cancelled() }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} diff --git a/.github/workflows/pr-build-workflow.yml b/.github/workflows/pr-build-workflow.yml deleted file mode 100644 index 6d56bc9d91..0000000000 --- a/.github/workflows/pr-build-workflow.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: PR Build - -on: pull_request - -env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }} - -permissions: - contents: read - -jobs: - build: - name: Build - runs-on: ubuntu-latest - if: ${{ github.repository == 'spring-projects/spring-security' }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Build with Gradle - run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue - generate-docs: - name: Generate Docs - runs-on: ubuntu-latest - if: ${{ github.repository == 'spring-projects/spring-security' }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: '17' - distribution: 'temurin' - - name: Run Antora - run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora - - name: Upload Docs - id: upload - uses: actions/upload-artifact@v4 - with: - name: docs - path: docs/build/site - overwrite: true - send-notification: - name: Send Notification - needs: [ build, generate-docs ] - if: ${{ failure() && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} diff --git a/.github/workflows/release-scheduler.yml b/.github/workflows/release-scheduler.yml deleted file mode 100644 index c58ee33e9c..0000000000 --- a/.github/workflows/release-scheduler.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Release Scheduler -on: - schedule: - - cron: '15 15 * * MON' # Every Monday at 3:15pm UTC - workflow_dispatch: -permissions: read-all -jobs: - dispatch_scheduled_releases: - name: Dispatch scheduled releases - if: github.repository_owner == 'spring-projects' - strategy: - matrix: - # List of active maintenance branches. - branch: [ main, 6.1.x, 5.8.x ] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - name: Dispatch - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }} diff --git a/.github/workflows/trigger-dependabot-auto-merge-forward.yml b/.github/workflows/trigger-dependabot-auto-merge-forward.yml deleted file mode 100644 index 9bbb2ccbd5..0000000000 --- a/.github/workflows/trigger-dependabot-auto-merge-forward.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Trigger Dependabot Auto Merge Forward - -on: - push: - branches: - - '*.x' - -permissions: read-all - -jobs: - trigger-worflow: - name: Trigger Workflow - runs-on: ubuntu-latest - if: ${{ github.event.commits[0].author.username == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }} - steps: - - name: Checkout - id: checkout - uses: actions/checkout@v4 - - id: trigger - env: - GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - run: gh workflow run dependabot-auto-merge-forward.yml -r main diff --git a/.github/workflows/update-scheduled-release-version.yml b/.github/workflows/update-scheduled-release-version.yml deleted file mode 100644 index 665b1b50b6..0000000000 --- a/.github/workflows/update-scheduled-release-version.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Update Scheduled Release Version - -on: - workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main. - -permissions: - contents: read - -jobs: - update-scheduled-release-version: - name: Update Scheduled Release Version - uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@v1 - secrets: inherit - send-notification: - name: Send Notification - needs: [ update-scheduled-release-version ] - if: ${{ failure() || cancelled() }} - runs-on: ubuntu-latest - steps: - - name: Send Notification - uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1 - with: - webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }} \ No newline at end of file From 5c92d90e36a35534deb20f0d24539bbe4c7ce168 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 14:59:08 -0500 Subject: [PATCH 130/504] Align Dependabot PRs with CONTRIBUTING Previously Dependabot was setup to submit PRs to every branch. However, this does not align with the contributing guidelines which state to only submit a PR on the oldest branch so that merge forward strategy can be used. This changes the dependabot configuration to better align with our contributing guidelines: - PRs for github actions are submitted against the oldest branch since all branches will need updated using a merge forward stategy. Merging a github action will require us to merge forward manually and preserve the changes in the oldest branch to pickup the github actions update. - Java dependencieds are submitted against each branch since they will need to merge -s ours to preserve the correct major.minor semantics. Merging a java dependency will now require us to do the merging manually. --- .github/dependabot.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4082d7441c..73b02a7c52 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -86,16 +86,6 @@ updates: update-types: - version-update:semver-major - - package-ecosystem: github-actions - target-branch: 6.4.x - directory: / - schedule: - interval: weekly - labels: - - 'type: task' - - 'in: build' - ignore: - - dependency-name: sjohnr/* - package-ecosystem: github-actions target-branch: 6.3.x directory: / @@ -106,14 +96,6 @@ updates: - 'in: build' ignore: - dependency-name: sjohnr/* - - package-ecosystem: github-actions - target-branch: main - directory: / - schedule: - interval: weekly - labels: - - 'type: task' - - 'in: build' - package-ecosystem: github-actions target-branch: docs-build directory: / From 51239359eda1f32ef328925762b99d9ddb81777d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 2 May 2025 15:57:31 -0600 Subject: [PATCH 131/504] Fix ClearSiteData Code Snippet Closes gh-16948 --- docs/modules/ROOT/pages/servlet/authentication/logout.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/authentication/logout.adoc b/docs/modules/ROOT/pages/servlet/authentication/logout.adoc index 4817bc382c..f8219472ab 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/logout.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/logout.adoc @@ -259,7 +259,7 @@ Java:: + [source,java,role="primary"] ---- -HeaderWriterLogoutHandler clearSiteData = new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter()); +HeaderWriterLogoutHandler clearSiteData = new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(Directives.ALL)); http .logout((logout) -> logout.addLogoutHandler(clearSiteData)) ---- @@ -268,7 +268,7 @@ Kotlin:: + [source,kotlin,role="secondary"] ---- -val clearSiteData = HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter()) +val clearSiteData = HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(Directives.ALL)) http { logout { addLogoutHandler(clearSiteData) From 9436796973cf4206f40e71d07fa7b3a54b7d2f16 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Mon, 5 May 2025 11:49:08 -0500 Subject: [PATCH 132/504] Use pull-request: write for gradlew updates Explicitly provide the permissions required for updating the Gradle wrapper --- .github/workflows/gradle-wrapper-upgrade-execution.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gradle-wrapper-upgrade-execution.yml b/.github/workflows/gradle-wrapper-upgrade-execution.yml index 85ae47b25a..a6e27801b5 100644 --- a/.github/workflows/gradle-wrapper-upgrade-execution.yml +++ b/.github/workflows/gradle-wrapper-upgrade-execution.yml @@ -4,7 +4,8 @@ on: schedule: - cron: '0 2 * * *' # 2am UTC workflow_dispatch: - +permissions: + pull-requests: write jobs: upgrade_wrapper: name: Execution From 97104926194b010701c2fc9bc3d4457f23bf9565 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Mon, 5 May 2025 13:34:16 -0500 Subject: [PATCH 133/504] remove update-dependabot action --- .github/dependabot.template.yml | 41 ------------------------- .github/workflows/update-dependabot.yml | 36 ---------------------- 2 files changed, 77 deletions(-) delete mode 100644 .github/dependabot.template.yml delete mode 100644 .github/workflows/update-dependabot.yml diff --git a/.github/dependabot.template.yml b/.github/dependabot.template.yml deleted file mode 100644 index 20976085e8..0000000000 --- a/.github/dependabot.template.yml +++ /dev/null @@ -1,41 +0,0 @@ -version: 2 - -registries: - spring-milestones: - type: maven-repository - url: https://repo.spring.io/milestone - -updates: - - - package-ecosystem: "gradle" - target-branch: "main" - directory: "/" - schedule: - interval: "daily" - time: "03:00" - timezone: "Etc/UTC" - labels: [ "type: dependency-upgrade" ] - registries: - - "spring-milestones" - ignore: - - dependency-name: "com.nimbusds:nimbus-jose-jwt" # nimbus-jose-jwt gets updated when oauth2-oidc-sdk is updated to ensure consistency - - dependency-name: "org.python:jython" # jython updates break integration tests - - dependency-name: "org.apache.directory.server:*" # ApacheDS version > 1.5.5 contains break changes - - dependency-name: "org.junit:junit-bom" - update-types: [ "version-update:semver-major" ] - - dependency-name: "org.mockito:mockito-bom" - update-types: [ "version-update:semver-major" ] - - dependency-name: "*" - update-types: [ "version-update:semver-major", "version-update:semver-minor" ] - - # GitHub Actions - - - package-ecosystem: github-actions - target-branch: "main" - directory: "/" - schedule: - interval: weekly - ignore: - - dependency-name: "sjohnr/*" - - dependency-name: "spring-io/*" - - dependency-name: "spring-security-release-tools/*" diff --git a/.github/workflows/update-dependabot.yml b/.github/workflows/update-dependabot.yml deleted file mode 100644 index 7b10563ec5..0000000000 --- a/.github/workflows/update-dependabot.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Update dependabot.yml - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - - get-supported-branches: - uses: spring-io/spring-security-release-tools/.github/workflows/retrieve-spring-supported-versions.yml@actions-v1 - with: - project: spring-security - type: oss - repository_name: spring-projects/spring-security - - main: - runs-on: ubuntu-latest - needs: [get-supported-branches] - if: ${{ (github.repository == 'spring-projects/spring-security') && (github.ref == 'refs/heads/main') }} - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - uses: spring-io/spring-security-release-tools/.github/actions/generate-dependabot-yml@actions-v1 - name: Update dependabot.yml - with: - gradle-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main - github-actions-branches: ${{ needs.get-supported-branches.outputs.supported_versions }},main,docs-build - gh-token: ${{ secrets.GITHUB_TOKEN }} - - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Update dependabot.yml From 34afa64c0cf4f774d85db90df73187ebca028f4a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 11:19:30 -0600 Subject: [PATCH 134/504] Add Current-Version Deserialization Test We should test that serialized files from the current minor version can be deserialized. This ensures that serializations remain deserializable in patch releases. Issue gh-3737 --- ...gSecurityCoreVersionSerializableTests.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index c4b96ab290..e8ee65af0a 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -690,7 +690,34 @@ class SpringSecurityCoreVersionSerializableTests { } @ParameterizedTest - @MethodSource("getFilesToDeserialize") + @MethodSource("getCurrentSerializedFiles") + void shouldBeAbleToDeserializeClassFromCurrentVersion(Path filePath) { + try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile()); + ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { + Object obj = objectInputStream.readObject(); + Class clazz = Class.forName(filePath.getFileName().toString().replace(".serialized", "")); + assertThat(obj).isInstanceOf(clazz); + } + catch (IOException | ClassNotFoundException ex) { + fail("Could not deserialize " + filePath, ex); + } + } + + static Stream getCurrentSerializedFiles() throws IOException { + assertThat(currentVersionFolder.toFile().exists()) + .as("Make sure that the " + currentVersionFolder + " exists and is not empty") + .isTrue(); + try (Stream files = Files.list(currentVersionFolder)) { + if (files.findFirst().isEmpty()) { + fail("Please make sure to run SpringSecurityCoreVersionSerializableTests#serializeCurrentVersionClasses for the " + + getPreviousVersion() + " version"); + } + } + return Files.list(currentVersionFolder); + } + + @ParameterizedTest + @MethodSource("getPreviousSerializedFiles") void shouldBeAbleToDeserializeClassFromPreviousVersion(Path filePath) { try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile()); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { @@ -703,7 +730,7 @@ class SpringSecurityCoreVersionSerializableTests { } } - static Stream getFilesToDeserialize() throws IOException { + static Stream getPreviousSerializedFiles() throws IOException { assertThat(previousVersionFolder.toFile().exists()) .as("Make sure that the " + previousVersionFolder + " exists and is not empty") .isTrue(); From 65d53beff8c3c5a58883c18ef1907d7f4b029aff Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 13:33:32 -0600 Subject: [PATCH 135/504] Polish Serialization Tests - Error when public, non-ignored, serializable file is missing a sample - Provide mechanism for creating an InstancioApi from scratch Issue gh-17038 --- ...gSecurityCoreVersionSerializableTests.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index e8ee65af0a..e053a6f730 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -16,6 +16,8 @@ package org.springframework.security; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -36,13 +38,17 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; import java.util.stream.Stream; import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.ObjectUtils; import org.apereo.cas.client.validation.AssertionImpl; import org.instancio.Instancio; import org.instancio.InstancioApi; @@ -63,6 +69,7 @@ import org.springframework.mock.web.MockHttpSession; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AuthorizationServiceException; import org.springframework.security.access.SecurityConfig; +import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException; import org.springframework.security.access.intercept.RunAsUserToken; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AccountExpiredException; @@ -94,15 +101,19 @@ import org.springframework.security.authentication.event.LogoutSuccessEvent; import org.springframework.security.authentication.jaas.JaasAuthenticationToken; import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent; import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent; +import org.springframework.security.authentication.ott.DefaultOneTimeToken; import org.springframework.security.authentication.ott.InvalidOneTimeTokenException; import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; import org.springframework.security.authentication.password.CompromisedPasswordException; import org.springframework.security.authorization.AuthorityAuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.security.authorization.event.AuthorizationEvent; +import org.springframework.security.authorization.event.AuthorizationGrantedEvent; import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; import org.springframework.security.cas.authentication.CasAuthenticationToken; import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken; +import org.springframework.security.config.annotation.AlreadyBuiltException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; @@ -128,11 +139,14 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authoriza import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; +import org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent; +import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent; import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.ClientSettings; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2AccessToken; @@ -148,6 +162,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; @@ -172,6 +187,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; @@ -188,8 +204,10 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2P import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens; import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests; import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests; import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests; +import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; @@ -213,6 +231,7 @@ import org.springframework.security.web.savedrequest.DefaultSavedRequest; import org.springframework.security.web.savedrequest.SimpleSavedRequest; import org.springframework.security.web.server.firewall.ServerExchangeRejectedException; import org.springframework.security.web.session.HttpSessionCreatedEvent; +import org.springframework.security.web.session.HttpSessionIdChangedEvent; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs; import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse; @@ -234,7 +253,9 @@ import org.springframework.security.web.webauthn.api.TestAuthenticationAssertion import org.springframework.security.web.webauthn.api.TestBytes; import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; @@ -262,6 +283,8 @@ class SpringSecurityCoreVersionSerializableTests { private static final Map, Generator> generatorByClassName = new HashMap<>(); + private static final Map, Supplier>> instancioByClassName = new HashMap<>(); + static final long securitySerialVersionUid = SpringSecurityCoreVersion.SERIAL_VERSION_UID; static Path currentVersionFolder = Paths.get("src/test/resources/serialized/" + getCurrentVersion()); @@ -766,10 +789,18 @@ class SpringSecurityCoreVersionSerializableTests { || Arrays.asList(suppressWarnings.value()).contains("Serial"); if (!hasSerialVersion && !hasSerialIgnore) { classes.add(clazz); + continue; + } + boolean isReachable = Modifier.isPublic(clazz.getModifiers()); + boolean hasSampleSerialization = currentVersionFolder.resolve(clazz.getName() + ".serialized") + .toFile() + .exists(); + if (hasSerialVersion && isReachable && !hasSampleSerialization) { + classes.add(clazz); } } - assertThat(classes) - .describedAs("Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings") + assertThat(classes).describedAs( + "Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings or a sample serialized file") .isEmpty(); } @@ -796,6 +827,9 @@ class SpringSecurityCoreVersionSerializableTests { } private static InstancioApi instancioWithDefaults(Class clazz) { + if (instancioByClassName.containsKey(clazz)) { + return instancioByClassName.get(clazz).get(); + } InstancioOfClassApi instancio = Instancio.of(clazz); ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics(); for (ResolvableType type : generics) { From 39fdceab594e14897cef58dbf3feb790f1f56636 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 13:36:21 -0600 Subject: [PATCH 136/504] Add Missing Serializable Samples Issue gh-17038 --- ...gSecurityCoreVersionSerializableTests.java | 80 ++++++++++++------ ...s.CycleInRoleHierarchyException.serialized | Bin 0 -> 10740 bytes ...zation.event.AuthorizationEvent.serialized | Bin 0 -> 1603 bytes ...event.AuthorizationGrantedEvent.serialized | Bin 0 -> 1692 bytes ...nnotation.AlreadyBuiltException.serialized | Bin 0 -> 10715 bytes ...ssion.HttpSessionIdChangedEvent.serialized | Bin 0 -> 421 bytes ...ropertiesOutput$ExtensionOutput.serialized | Bin 0 -> 115 bytes 7 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index e053a6f730..c9843c7ed6 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -16,8 +16,6 @@ package org.springframework.security; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -38,7 +36,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -48,7 +45,6 @@ import java.util.function.Supplier; import java.util.stream.Stream; import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.ObjectUtils; import org.apereo.cas.client.validation.AssertionImpl; import org.instancio.Instancio; import org.instancio.InstancioApi; @@ -139,14 +135,11 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authoriza import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; -import org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent; -import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent; import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistration.ClientSettings; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2AccessToken; @@ -162,7 +155,6 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; -import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; @@ -187,7 +179,6 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; -import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; @@ -253,9 +244,7 @@ import org.springframework.security.web.webauthn.api.TestAuthenticationAssertion import org.springframework.security.web.webauthn.api.TestBytes; import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; @@ -417,6 +406,9 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(OAuth2IntrospectionException.class, (r) -> new OAuth2IntrospectionException("message", new RuntimeException())); + // config + generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message")); + // core generatorByClassName.put(RunAsUserToken.class, (r) -> { RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(), @@ -508,6 +500,20 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true)); generatorByClassName.put(AuthorityAuthorizationDecision.class, (r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER"))); + generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException()); + generatorByClassName.put(AuthorizationEvent.class, + (r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + generatorByClassName.put(AuthorizationGrantedEvent.class, + (r) -> new AuthorizationGrantedEvent<>(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + instancioByClassName.put(AuthorizationGrantedEvent.class, () -> { + InstancioOfClassApi instancio = Instancio.of(AuthorizationGrantedEvent.class); + instancio.withTypeParameters(String.class); + instancio.supply(Select.all(AuthorizationGrantedEvent.class), + generatorByClassName.get(AuthorizationGrantedEvent.class)); + return instancio; + }); // cas generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> { @@ -561,6 +567,7 @@ class SpringSecurityCoreVersionSerializableTests { token.setDetails(details); return token; }); + generatorByClassName.put(Saml2LogoutRequest.class, (r) -> TestSaml2LogoutRequests.create()); // web generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> { @@ -616,20 +623,8 @@ class SpringSecurityCoreVersionSerializableTests { request.addPreferredLocale(Locale.ENGLISH); return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue")); }); - - // webauthn - generatorByClassName.put(Bytes.class, (r) -> TestBytes.get()); - generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, - (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); - generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() - .id(TestBytes.get()) - .build(); - List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); - WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); - webAuthnAuthentication.setDetails(details); - return webAuthnAuthentication; - }); + generatorByClassName.put(HttpSessionIdChangedEvent.class, + (r) -> new HttpSessionIdChangedEvent(new MockHttpSession(), "1")); // webauthn CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect( @@ -686,6 +681,25 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken); generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM); // @formatter:on + generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, + (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); + generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() + .id(TestBytes.get()) + .build(); + List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); + WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); + webAuthnAuthentication.setDetails(details); + return webAuthnAuthentication; + }); + // @formatter:on + generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class, + (r) -> new CredentialPropertiesOutput(true).getOutput()); + + // One-Time Token + DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user", + Instant.now().plusSeconds(300)); + generatorByClassName.put(DefaultOneTimeToken.class, (t) -> oneTimeToken); } @ParameterizedTest @@ -862,4 +876,20 @@ class SpringSecurityCoreVersionSerializableTests { return String.join(".", parts); } + @SuppressWarnings("serial") + private static final class SerializableSupplier implements Supplier, Serializable { + + private final T value; + + SerializableSupplier(T value) { + this.value = value; + } + + @Override + public T get() { + return this.value; + } + + } + } diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..43d7d327459fd83c9d89098ee53f0a9643b66db0 GIT binary patch literal 10740 zcmeHNU2Gjk6`t!Pj$`sqQs=jE(oIr`x^dz(KXux~wVlMN;{;zPkhT=9_l~dE-n+Zm zo$L6979`q&Kva|>`cR>YAE62f1gM1u^_5geeSwEQ@Bl)ns1g#qAn||{!Z|auv$H?< z`kIC(;)n6<%$ak}eCN!WIWzaie!IKb{aOir?Pe_1Lz79ly>|OwNSd zp1i&11VR@OLVf_&-kw058(^)v_1eCpe|WKjbUjWwr~R;Iu~E|PIvyRb*QRJVM%LM` z6-8sdRiWWHI1A2b#TZ#zq0oWo4Pn1*?V5I6s!?^}t@E96@c@GIAUhbUdK(Y{!QhqoHTHW|exdh?pOmH7Byov+?IJ zwSC^sNKd{|O74=QsV?!nl=xT^i8Gd0aREv5azw*2c&Y2qiV|@t^l@$bAtMj8CXhO8 zgaxBUPtd6DGF_XaQk#?il{V*uu8iz1)J1knO;&*>c?F)A3hZm5fYSYpWrG7VvMJNT zxg(RU`n;axY_ZsdMK2>8s={`3+^^6pmRr}Y((y8U4h-odyGE zv=+F4maHjzAJW;pr4Z@I+7U)Ng;b5G<2^;R4r}XSpMW*SBMcp?haqeYGVt(-NTYZ# zxdVR?#vYoj%q6iQq|+`~E)EK`a)F1+LB9L?;b9oi>3H-0obogX>f``4A1dTCOkG-q z80A&djKutRx9V1)3^1~a?-o-Q?x>xIj+uRCzle7rz2i7Y-;!)6@f3tWMm{Dg2|L8; z6c(pd%DW}C*f%3*V)K| zY=C)Zo8-J#@m&qo)n$E)%fjLk7N3F*P0`_=i+gY0GSB2jZBLDwq_AiqxaCJy`A9~d zYzt{HH9wwu)e&xK)CSR%0DIJ^fL2MLt&m0Bb~Q(EWif)^a{@;A zIj0ca3XSa0!KG}X+Y86V+OXYNF2Ty@L`9`VBN)a2?=7UJTuW*{dnggd};fsl?x}smpkmIMP6AUj#5J$3s zB~BF&X{ghr70tofP5+eB+b*G&vz)-}A#&!a+b~imd;vD<>0(jK&EXX_2ZpseBQ02` z?D$nak`ZltYRir|8`!7upPWpm75a5AwIhiWDN1NVtrNOY7M<}oax>nTM^Wck$qc~H zlpj362^jgz63twObQBzzT9x=d0xv7j@FHmYA*6uw4yN>G+q5yJQGKfBr1rWGrJ7fk zsHX0I#xR|>Ad4Dqcvj7^bzPBrJ%`QjxKJ#(zvKyC;slKFjIf>96mPC5TaQk=_==G` zZ@QCXl2eT@27XrmI`+MkB+JqtjQ-dS@aXzB93Btw!y`Z5MGOpAGtcN;JHv*jTB6u0csUhtm)6gf$o>|v-= zGF(W&X$$W}U{hDk(!A>-3qWs}pf%X-;qZkJWNgv#FA%an5hDF4XHerD#08EsBP%7} z0(PZMZJPGjT`_H2_HT!1*`LxdXuw7SZmk9OKqU;@sF zt#2rzqLmM;4Ew)}#rLpiVnyr{Kx6IaSY(z`Nw)^}zga*82Ef)|V8NqNAy7+36WRT$ zKpfzRt?yv*(Qtwt0hufkYwsG-J+qK|?n@STUreO3CnxmN)QR{2wrEGI9D&G;uvwh% zu{Ix{wot^P$M|gGf*cw;2a%s(^XIX67K`U}f|s#{E1Br*Lev#+i2P8g4iw0V2gh8PMQ}c$G=C9mUxsu_B(j69tBdC`HZ#NjPm~d+KQ9eb zr2gO@n)!@Pq`L@@@II`4MF;8xw!pI@fA`E>k+-_xX_f`U%~P{3mG-2<&rzws$PzQ% zoD})owY|8bSophAxOUm5?nPXy?%6YNfe-Je)D*92BG-q@?2GVg1;}Y-a?#tOw^;Cx zxL_>qKv5!COTi*8bXyQSf_*$*2oCv-ICViRQul-(iLJ`RIf<9sI#g zJ&qglf)q9b)k&lHN{JC;k?~wx$dC9#Q52=w#OoXuBMjC6}1-WYv-%1Myu z8JH#i!OmTtrIflnVt$}2bqeJ1JN?DwmFtkpD~J?+jO=LA6Wg)W6HDxXr_q0d#NxNn zad-@ym#;wa!>D-A+}W&4g1=Ji=Y8mjnXHFg;IQvN0Cr;kKoQXaBqEPu@mMn=cn`&{ z$FUeHBtiokFg^a*DFJojUx!qjD6p74qrG$v%O<#)hs+Ug=^?JgjdE&T@wga66tacS z33rx~fyG|Eb2n&kOj{^<4Tj*wlP-vLAb#o-3x)T`=AFu(DREDOxbc?az*QC+v4p{j z6~L8{5r4yaP2Qf=?+LaRjfv$a?>+Hb`$l{thXuIMIBXhx=uwVP53IAKOa7Dx0sIXp zeL_>ZMKHmi%fS|ej{j+1HTvNyBl(neS{Bw-Tt*2mWUR0h324&8u&(6ADqNXdfD1DC zS(_*BzwrlFy2Yz}vJdlNP$U}!Dsrk-CqD7>t7Pe|fFb`mpz;|xd-!3XTQLW@gQ^`^ zz`@A2!ggh?6f8GD;1e3~tp%1F5u>$1{9TiHsOOdgEr#TPNRm{g03zEd&ey0VmWb^8f$< literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..568c4a3ac20bce16fcb82e8b004f27231125c6e3 GIT binary patch literal 1603 zcmb7EJ7^S96urCIWV3{PHKIbS60wjOv@}gVu8T4xA+syGis9|-%leY}<;|O95=o3A z_yHp*iXs+TiP~yuYatez+9I{4v9VF`zS&)7Him>uG4L+;bM86ky?2|?>~R=%ct!DC z&g{xGCl+0B_^jel!{xIG2Q^1|6~n zgUkqv1oUY$WS*$LV5U0l+lFkV>b~omjPgMZS~&H5QwSK+5R1A6i(1E`HegX3P)vp$ z1_KVqw_C?>Y(WD=E@xI@g}6(%eoWoTec4Dt;v8fIv#2MCG(!!c z-Or32w3c5d0Rk5w@#N*N%q!&Z@^(Y(xD`DlSFcfueADxkdq{##IU^>LTQX@LM|=J8 zNS&el(%}zp*V->2NDZ3jiRn`TJylLkVpr5Ew!y$fB;z|GX;eljc$C{H`2_Jil)Wq| zjfBfPv($$0OPZmwZ3d@hnLtc$4ptzoK}POoFqfEN0GZ3}1;KF16Py@go5|~Mj;+|a zaz_%HiqIZIPRkm!$us&=Fr*C*#0)m-m?kQP?4q;MWhw}(feqXQ5_B{YHcIvS3%2Ey z*))?h=FkYNe!lYiNZ2%CNXFVi)%HbQ zhB+sTvU_mjTi>%!tmj%(Sef}WiWB<>zpy6xod5PbAlO@+{J(a3ZWx`|;p zzAeTaI~%wR-BpCHD5g2atPJ(Wd>2nmQ(NlwpC3A7Lg`eX5nA1v#U=Lrc$ToF^}{nd z13%nnAkraHtBOVQo3}4D$+rSC&g`A5 zet9iIp++6cC7cL{NBm*isuv`N-atUdHQRCA<@%}uQgTZiJ+$NK+EuDO@wJiF(`jlj X`B1H&+OS&5T|na&Azi7u2wD3Fm7qFw literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6d3ca9608f9cacaa523776a846715debb31b4d0c GIT binary patch literal 1692 zcmbtVO-vI}5T2GIG{~Q%L{0Dn#)H{LkCGUEtc_#?gtkV}Kwh^Ge6ZbJ-oAx`0nwPC zCSsz|Xp9GMMvXT;di7vDC}&JKD;FrJS2B@Ebd zQga3VL+J65ldpygX#QYRGuicq4v=ZXD36gQN9H#&GQzxaZfa{xk*p8trxL2)i`*R+gV zOZlp$N?IY`{5+Q~l91w3FcVeFnmmoI-OkELnW6N;;difA8!sS89cpKp>2U=IikzCv znv55*br&2&GPEO-YGt&H%cX^08fLDGe##N0fpBSinp@yMVbfQ(!H_&h3Cwh7UAd#x*pijZHHD#O6dEg#^PCP1bVkD~fwVz;g~9r5 z(?q3^U36Amjw>cgU<*zN2|5}G8>G6O87pt+#DpLzbm6LB&0QzneqU|zNspKqQP5J+ zhH`wn?OrZubEprNKaTx8;uj4W#MpjcwYH#2uas<_su!+*>3H&iJ*$DxIf%Gofs^GR zG#8;?oTP6@q7AfJc`e|ANQt~-^3oO{wu!v?KwY#}MB3&SXQdSF8+4X}=*WGh8vnk$4#afL>xcS;r~>@hqOEV90TMrYuI^K=C|1gce=1M4k!-2Z&<>2ij)0NroF zo2|jkwB#JK)*lZ)c(}Q8sfKn1W}MwSSDk-_>bLU_lT6t%;1A0dy+9b+3ksU9TDI*h vmPb_(p((L-&yKB2f2Gp5qtvo^I>QY?i)!uEM!ufi1~l#{)J+z@CCJ(zGiF^1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d3344aeda54a287d2730736f895487bb3cf89a2f GIT binary patch literal 10715 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 L7?_H(D+(9^Dt9X> literal 0 HcmV?d00001 From c3c2bcd6b7240fee6d5bc9c90be2c9023badcc75 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 12:19:55 -0600 Subject: [PATCH 137/504] Ignore Serialization in Test Components Since we don't need to ensure the serializability of test components across versions, we can ignore missing version UIDs when those test components aren't about testing Java serialization. Issue gh-17038 --- .../SpringSecurityCoreVersionSerializableTests.java | 10 ++-------- .../config/annotation/method/configuration/Authz.java | 1 + .../access/annotation/BusinessServiceImpl.java | 5 +---- .../ExpressionProtectedBusinessServiceImpl.java | 5 +---- .../access/annotation/Jsr250BusinessServiceImpl.java | 5 +---- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index c9843c7ed6..2712617475 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -740,17 +740,11 @@ class SpringSecurityCoreVersionSerializableTests { } } - static Stream getCurrentSerializedFiles() throws IOException { + static Stream getCurrentSerializedFiles() throws Exception { assertThat(currentVersionFolder.toFile().exists()) .as("Make sure that the " + currentVersionFolder + " exists and is not empty") .isTrue(); - try (Stream files = Files.list(currentVersionFolder)) { - if (files.findFirst().isEmpty()) { - fail("Please make sure to run SpringSecurityCoreVersionSerializableTests#serializeCurrentVersionClasses for the " - + getPreviousVersion() + " version"); - } - } - return Files.list(currentVersionFolder); + return getClassesToSerialize().map((clazz) -> currentVersionFolder.resolve(clazz.getName() + ".serialized")); } @ParameterizedTest diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java index 145f344d12..5b6c784c7f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java @@ -55,6 +55,7 @@ public class Authz { return Mono.just(checkResult(result)); } + @SuppressWarnings("serial") public static class AuthzResult extends AuthorizationDecision { public AuthzResult(boolean granted) { diff --git a/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java index 587e795f5a..1bcf1ba84d 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java @@ -16,18 +16,15 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; /** * @author Joe Scalise */ +@SuppressWarnings("serial") public class BusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -4249394090237180795L; - @Override @Secured({ "ROLE_USER" }) public void someUserMethod1() { diff --git a/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java index 1ca226709b..1c6fd2a84e 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java @@ -16,7 +16,6 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -24,11 +23,9 @@ import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; +@SuppressWarnings("serial") public class ExpressionProtectedBusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -3320014879907436606L; - @Override public void someAdminMethod() { } diff --git a/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java index 6d9f34ac61..4eba9445a6 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java @@ -16,7 +16,6 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -27,11 +26,9 @@ import jakarta.annotation.security.RolesAllowed; * @author Luke Taylor */ @PermitAll +@SuppressWarnings("serial") public class Jsr250BusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -7550211450382764339L; - @Override @RolesAllowed("ROLE_USER") public void someUserMethod1() { From 2949b5d5a489e033dacc446e21ec441f4e422460 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 11:31:01 -0600 Subject: [PATCH 138/504] Regenerate Incorrect Serialization Files Given that these classes each have a consistent serialization UID across minor versions, but that the 6.5.x serialized version is using a different UID, these serialized files were likely generated in error. As such, this commit replaces the serialized files with correct ones. Issue gh-16432 --- ...security.web.webauthn.api.Bytes.serialized | Bin 140 -> 140 bytes ...i.PublicKeyCredentialDescriptor.serialized | Bin 688 -> 688 bytes ...blicKeyCredentialRequestOptions.serialized | Bin 1833 -> 1833 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.Bytes.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.Bytes.serialized index e45bced432312c60e07be3bd55dfd6d155ea2350..3f268bddcd4691a3b16f695bb36970d33abfe294 100644 GIT binary patch delta 18 ZcmeBS>|vZ>&2g!5o4v-d1^N@6Jpn+G2M_=N delta 18 ZcmeBS>|vZ>%`ubZQ{x9^hlLZJJpn%U2M+)M diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor.serialized index 7de3d58f80bdf15cea8d34d0ef56d0f74bef45b7..70911ad2c17d1291742401548f118838a72c3aa6 100644 GIT binary patch delta 21 dcmdnMx`B0r3nRy+#%=Z*#}?>s_F+t61OQr12hsol delta 21 dcmdnMx`B0r3nRx&mQRfzlpPjs_F+t61OQmD2hjik diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions.serialized index 399fa41229196ab1c517a82a6f6bd02e146801e4..40415ad5dfe779d59650f4b9421c6e5c25e34b24 100644 GIT binary patch delta 21 dcmZ3s7H1Y>0RUC%2O$6e delta 21 dcmZ30RU7@2Ot0d From 8726e547d546a9552c5767ade6bbc10a1a375069 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 15:24:58 -0600 Subject: [PATCH 139/504] Add Serialization Samples for 6.5 Issue gh-16221 --- ...rity.access.AccessDeniedException.serialized | Bin 0 -> 16530 bytes ...ess.AuthorizationServiceException.serialized | Bin 0 -> 16610 bytes ...rk.security.access.SecurityConfig.serialized | Bin 0 -> 109 bytes ...les.CycleInRoleHierarchyException.serialized | Bin 0 -> 11098 bytes ...y.access.intercept.RunAsUserToken.serialized | Bin 0 -> 1379 bytes ...ntication.AccountExpiredException.serialized | Bin 0 -> 16839 bytes ...tion.AnonymousAuthenticationToken.serialized | Bin 0 -> 787 bytes ...ationCredentialsNotFoundException.serialized | Bin 0 -> 16777 bytes ...on.AuthenticationServiceException.serialized | Bin 0 -> 16765 bytes ...ntication.BadCredentialsException.serialized | Bin 0 -> 16758 bytes ...ation.CredentialsExpiredException.serialized | Bin 0 -> 16843 bytes ....authentication.DisabledException.serialized | Bin 0 -> 16833 bytes ...sufficientAuthenticationException.serialized | Bin 0 -> 16770 bytes ...nalAuthenticationServiceException.serialized | Bin 0 -> 16862 bytes ...ty.authentication.LockedException.serialized | Bin 0 -> 16831 bytes ...ication.ProviderNotFoundException.serialized | Bin 0 -> 11213 bytes ...ion.RememberMeAuthenticationToken.serialized | Bin 0 -> 1200 bytes ...cation.TestingAuthenticationToken.serialized | Bin 0 -> 534 bytes ...ernamePasswordAuthenticationToken.serialized | Bin 0 -> 1118 bytes ...icationFailureBadCredentialsEvent.serialized | Bin 0 -> 11700 bytes ...ionFailureCredentialsExpiredEvent.serialized | Bin 0 -> 11789 bytes ...uthenticationFailureDisabledEvent.serialized | Bin 0 -> 11769 bytes ...AuthenticationFailureExpiredEvent.serialized | Bin 0 -> 11774 bytes ....AuthenticationFailureLockedEvent.serialized | Bin 0 -> 11765 bytes ...ationFailureProviderNotFoundEvent.serialized | Bin 0 -> 11704 bytes ...icationFailureProxyUntrustedEvent.serialized | Bin 0 -> 11707 bytes ...ationFailureServiceExceptionEvent.serialized | Bin 0 -> 11709 bytes ....event.AuthenticationSuccessEvent.serialized | Bin 0 -> 304 bytes ...ractiveAuthenticationSuccessEvent.serialized | Bin 0 -> 414 bytes ...tication.event.LogoutSuccessEvent.serialized | Bin 0 -> 296 bytes ...tion.jaas.JaasAuthenticationToken.serialized | Bin 0 -> 1205 bytes ...ication.jaas.JaasGrantedAuthority.serialized | Bin 0 -> 166 bytes ...ent.JaasAuthenticationFailedEvent.serialized | Bin 0 -> 11326 bytes ...nt.JaasAuthenticationSuccessEvent.serialized | Bin 0 -> 314 bytes ....ott.InvalidOneTimeTokenException.serialized | Bin 0 -> 11220 bytes ...t.OneTimeTokenAuthenticationToken.serialized | Bin 0 -> 699 bytes ...word.CompromisedPasswordException.serialized | Bin 0 -> 16772 bytes ...on.AuthorityAuthorizationDecision.serialized | Bin 0 -> 400 bytes ...thorization.AuthorizationDecision.serialized | Bin 0 -> 96 bytes ...tion.AuthorizationDeniedException.serialized | Bin 0 -> 11307 bytes ...rization.event.AuthorizationEvent.serialized | Bin 0 -> 1603 bytes ...n.event.AuthorizationGrantedEvent.serialized | Bin 0 -> 1692 bytes ...n.CasAssertionAuthenticationToken.serialized | Bin 0 -> 1454 bytes ...entication.CasAuthenticationToken.serialized | Bin 0 -> 2094 bytes ...sServiceTicketAuthenticationToken.serialized | Bin 0 -> 552 bytes ....annotation.AlreadyBuiltException.serialized | Bin 0 -> 11073 bytes ....authority.SimpleGrantedAuthority.serialized | Bin 0 -> 125 bytes ....core.context.SecurityContextImpl.serialized | Bin 0 -> 153 bytes ....context.TransientSecurityContext.serialized | Bin 0 -> 1294 bytes ...core.session.AbstractSessionEvent.serialized | Bin 0 -> 198 bytes ...ession.ReactiveSessionInformation.serialized | Bin 0 -> 867 bytes ...y.core.session.SessionInformation.serialized | Bin 0 -> 849 bytes ...rdetails.User$AuthorityComparator.serialized | Bin 0 -> 91 bytes ...rk.security.core.userdetails.User.serialized | Bin 0 -> 299 bytes ...details.UsernameNotFoundException.serialized | Bin 0 -> 16762 bytes ...dap.ppolicy.PasswordPolicyControl.serialized | Bin 0 -> 96 bytes ...p.ppolicy.PasswordPolicyException.serialized | Bin 0 -> 11328 bytes ...icy.PasswordPolicyResponseControl.serialized | Bin 0 -> 506 bytes ...ty.ldap.userdetails.InetOrgPerson.serialized | Bin 0 -> 1199 bytes ...ty.ldap.userdetails.LdapAuthority.serialized | Bin 0 -> 265 bytes ...p.userdetails.LdapUserDetailsImpl.serialized | Bin 0 -> 401 bytes ....security.ldap.userdetails.Person.serialized | Bin 0 -> 656 bytes ...ient.ClientAuthorizationException.serialized | Bin 0 -> 16940 bytes ...entAuthorizationRequiredException.serialized | Bin 0 -> 11626 bytes ...2.client.OAuth2AuthorizedClientId.serialized | Bin 0 -> 171 bytes ...ication.OAuth2AuthenticationToken.serialized | Bin 0 -> 1657 bytes ...entication.logout.OidcLogoutToken.serialized | Bin 0 -> 895 bytes ...dc.session.OidcSessionInformation.serialized | Bin 0 -> 2430 bytes ....oauth2.core.AuthenticationMethod.serialized | Bin 0 -> 123 bytes ...auth2.core.AuthorizationGrantType.serialized | Bin 0 -> 121 bytes ...2.core.ClientAuthenticationMethod.serialized | Bin 0 -> 126 bytes ...faultOAuth2AuthenticatedPrincipal.serialized | Bin 0 -> 1225 bytes ....core.OAuth2AccessToken$TokenType.serialized | Bin 0 -> 126 bytes ...ity.oauth2.core.OAuth2AccessToken.serialized | Bin 0 -> 733 bytes ...ore.OAuth2AuthenticationException.serialized | Bin 0 -> 16972 bytes ...core.OAuth2AuthorizationException.serialized | Bin 0 -> 16821 bytes ....security.oauth2.core.OAuth2Error.serialized | Bin 0 -> 159 bytes ...point.OAuth2AuthorizationExchange.serialized | Bin 0 -> 2008 bytes ...dpoint.OAuth2AuthorizationRequest.serialized | Bin 0 -> 1469 bytes ...point.OAuth2AuthorizationResponse.serialized | Bin 0 -> 462 bytes ...t.OAuth2AuthorizationResponseType.serialized | Bin 0 -> 140 bytes ...rity.oauth2.core.oidc.OidcIdToken.serialized | Bin 0 -> 682 bytes ...ity.oauth2.core.oidc.OidcUserInfo.serialized | Bin 0 -> 328 bytes ...h2.core.oidc.user.DefaultOidcUser.serialized | Bin 0 -> 2051 bytes ....core.oidc.user.OidcUserAuthority.serialized | Bin 0 -> 1313 bytes ...auth2.core.user.DefaultOAuth2User.serialized | Bin 0 -> 968 bytes ...th2.core.user.OAuth2UserAuthority.serialized | Bin 0 -> 417 bytes ...curity.oauth2.jwt.BadJwtException.serialized | Bin 0 -> 16587 bytes ...framework.security.oauth2.jwt.Jwt.serialized | Bin 0 -> 831 bytes ...JwtDecoderInitializationException.serialized | Bin 0 -> 16540 bytes ...y.oauth2.jwt.JwtEncodingException.serialized | Bin 0 -> 16594 bytes ....security.oauth2.jwt.JwtException.serialized | Bin 0 -> 16519 bytes ...oauth2.jwt.JwtValidationException.serialized | Bin 0 -> 11427 bytes ...ce.BearerTokenAuthenticationToken.serialized | Bin 0 -> 781 bytes ....server.resource.BearerTokenError.serialized | Bin 0 -> 473 bytes ...ource.InvalidBearerTokenException.serialized | Bin 0 -> 17355 bytes ...ication.BearerTokenAuthentication.serialized | Bin 0 -> 3022 bytes ...on.BearerTokenAuthenticationToken.serialized | Bin 0 -> 684 bytes ...entication.JwtAuthenticationToken.serialized | Bin 0 -> 1554 bytes ...ospection.BadOpaqueTokenException.serialized | Bin 0 -> 16665 bytes ...trospectionAuthenticatedPrincipal.serialized | Bin 0 -> 1434 bytes ...tion.OAuth2IntrospectionException.serialized | Bin 0 -> 16561 bytes ...security.provisioning.MutableUser.serialized | Bin 0 -> 190 bytes ...ork.security.saml2.Saml2Exception.serialized | Bin 0 -> 16611 bytes ...rk.security.saml2.core.Saml2Error.serialized | Bin 0 -> 145 bytes ...ty.saml2.core.Saml2X509Credential.serialized | Bin 0 -> 1623 bytes ...efaultSaml2AuthenticatedPrincipal.serialized | Bin 0 -> 357 bytes ...uthentication.Saml2Authentication.serialized | Bin 0 -> 1187 bytes ...tion.Saml2AuthenticationException.serialized | Bin 0 -> 17070 bytes ...tication.Saml2AuthenticationToken.serialized | Bin 0 -> 6302 bytes ...on.Saml2PostAuthenticationRequest.serialized | Bin 0 -> 417 bytes ...aml2RedirectAuthenticationRequest.serialized | Bin 0 -> 473 bytes ...ication.logout.Saml2LogoutRequest.serialized | Bin 0 -> 736 bytes ...egistration$AssertingPartyDetails.serialized | Bin 0 -> 2621 bytes ...stration.RelyingPartyRegistration.serialized | Bin 0 -> 5860 bytes ...tication.WebAuthenticationDetails.serialized | Bin 0 -> 162 bytes ...eAuthenticatedAuthenticationToken.serialized | Bin 0 -> 1231 bytes ...catedCredentialsNotFoundException.serialized | Bin 0 -> 16834 bytes ...thoritiesWebAuthenticationDetails.serialized | Bin 0 -> 385 bytes ...n.rememberme.CookieTheftException.serialized | Bin 0 -> 11333 bytes ...rememberme.InvalidCookieException.serialized | Bin 0 -> 11335 bytes ...RememberMeAuthenticationException.serialized | Bin 0 -> 16826 bytes ...on.SessionAuthenticationException.serialized | Bin 0 -> 11233 bytes ...on.SessionFixationProtectionEvent.serialized | Bin 0 -> 382 bytes ...ser.AuthenticationSwitchUserEvent.serialized | Bin 0 -> 1016 bytes ...chuser.SwitchUserGrantedAuthority.serialized | Bin 0 -> 203 bytes ...ication.www.NonceExpiredException.serialized | Bin 0 -> 16807 bytes ...k.security.web.csrf.CsrfException.serialized | Bin 0 -> 11077 bytes ...ecurity.web.csrf.DefaultCsrfToken.serialized | Bin 0 -> 172 bytes ...eb.csrf.InvalidCsrfTokenException.serialized | Bin 0 -> 11241 bytes ...eb.csrf.MissingCsrfTokenException.serialized | Bin 0 -> 11227 bytes ...firewall.RequestRejectedException.serialized | Bin 0 -> 11020 bytes ....savedrequest.DefaultSavedRequest.serialized | Bin 0 -> 1787 bytes ...rity.web.savedrequest.SavedCookie.serialized | Bin 0 -> 250 bytes ...b.savedrequest.SimpleSavedRequest.serialized | Bin 0 -> 1022 bytes ...ity.web.server.csrf.CsrfException.serialized | Bin 0 -> 11084 bytes ....web.server.csrf.DefaultCsrfToken.serialized | Bin 0 -> 179 bytes ...l.ServerExchangeRejectedException.serialized | Bin 0 -> 11034 bytes ...b.session.HttpSessionCreatedEvent.serialized | Bin 0 -> 354 bytes ...session.HttpSessionIdChangedEvent.serialized | Bin 0 -> 421 bytes ...pi.AuthenticatorAssertionResponse.serialized | Bin 0 -> 783 bytes ...authn.api.AuthenticatorAttachment.serialized | Bin 0 -> 130 bytes ...lPropertiesOutput$ExtensionOutput.serialized | Bin 0 -> 115 bytes ...hn.api.CredentialPropertiesOutput.serialized | Bin 0 -> 306 bytes ...enticationExtensionsClientOutputs.serialized | Bin 0 -> 619 bytes ...ablePublicKeyCredentialUserEntity.serialized | Bin 0 -> 361 bytes ....webauthn.api.PublicKeyCredential.serialized | Bin 0 -> 2288 bytes ...entication.WebAuthnAuthentication.serialized | Bin 0 -> 1185 bytes ...ebAuthnAuthenticationRequestToken.serialized | Bin 0 -> 4101 bytes ...RelyingPartyAuthenticationRequest.serialized | Bin 0 -> 3406 bytes 150 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.access.AccessDeniedException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.access.AuthorizationServiceException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.access.SecurityConfig.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.access.intercept.RunAsUserToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AccountExpiredException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AuthenticationCredentialsNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AuthenticationServiceException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.BadCredentialsException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.CredentialsExpiredException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.DisabledException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.LockedException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ProviderNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureLockedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.JaasGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.InvalidOneTimeTokenException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorityAuthorizationDecision.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDecision.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.SecurityContextImpl.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.TransientSecurityContext.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.AbstractSessionEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.SessionInformation.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.User$AuthorityComparator.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.User.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.InetOrgPerson.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.Person.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.ClientAuthorizationRequiredException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClientId.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.AuthorizationGrantType.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AccessToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2Error.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.OidcIdToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.user.DefaultOAuth2User.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.Jwt.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtDecoderInitializationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.InvalidBearerTokenException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.provisioning.MutableUser.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.Saml2Exception.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.core.Saml2Error.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.core.Saml2X509Credential.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.InvalidCookieException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.session.SessionFixationProtectionEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.CsrfException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.DefaultCsrfToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.firewall.RequestRejectedException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SavedCookie.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.server.csrf.CsrfException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.server.csrf.DefaultCsrfToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.server.firewall.ServerExchangeRejectedException.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest.serialized diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.AccessDeniedException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.AccessDeniedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..77c4777bd73dcee52f0f4fa7698f65fbf1998190 GIT binary patch literal 16530 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 F{|8&MHMz7Xv!qflF*!N4xL7Y3%6HDs zOUq23^C9;|nf9jwCI&_y2DZeKlA_F{5(Xikti-ZJ{hY+Sbp2qUP+q!qML`JzYguAW GX(|8>RVfkx literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e1dd1cc40a26bcb8c63a5e986b39909382668748 GIT binary patch literal 11098 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 PKlZg(eh>T3nP}#}f%Lc6 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.intercept.RunAsUserToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.access.intercept.RunAsUserToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8394c9a73882da2af97a15c33d066ec75d9efa91 GIT binary patch literal 1379 zcmb7E&rj4q82#E^TnOQpMiLKr0^`Ay$Q3UOB9JsJUj zCK?ls(Lca=^>6UtNj>`?$k~erzv%+g)nti1H0|`8?|bjfd;NF>16siishWXK6cf#D zMcQ;Bc{bxqZVY*7LE<#Qj(t59jt&I-{xAq+=~ z##9(axHfP;+$DQtmJ`vOU2E*p$jpZ@DHUrnL3lMaJGL|;hDl*yqENlaiPl&=WZ^|D zA^ZUxfR`y)?vJ{sXHacuqex_WN96>*f4F)emg7+$N}Di3+&&s34f~Eb4Wme7vI{IV zjL$Ag&XETKMs$^!8p62lVoN*}^@?R2*wVn2>gl>@%b0C5(%>{?+Wa1yx&G3w?!-q@uxzN}Zs_+6kx2ilAL$tF{%d<4j^%D#>ZDCu+u; zZ$3*546Uz)OI!8Y(t2ib4>>iJU;fFAyXj>XujbnxW zwzEdiW*VRIOjqN4!2&whtwUs|-@tpnWnjQsT<@KQ&uZh41XUqLr!7<6i?EO-@OUqnUxx PM?%Wv@d;G}Wy|spgi6*U literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AccountExpiredException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AccountExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..ad4812a76de5d41666c0f4535669f1cfe91a67d0 GIT binary patch literal 16839 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 Dh5S$w literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e8872447c4e4b79e806c9228b3fd7a09c546b6fa GIT binary patch literal 787 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AuthenticationServiceException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.AuthenticationServiceException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4a1ed3a3e64d0287fc776ce653e8a2acb031bbad GIT binary patch literal 16765 zcmeHNX^dRO5$;*v#x{%bZG&Tbd<4T=-v>6BWp{nCKGB%)H^fp7pMC zNMI6$C<2s32oR7E84^$qL_nZ~B#MHQp!^9Ek)lW;QKSfgl3)23i6r%P_v_d1n4MW{ z@yFgDwQststE#K2yQ{1E2mfMI0-qi9{9!Ao`EGT1$hRxbY0p1p1x}&vyL`;D>%8Pt zxm&Qg>s77J*w22)A8`v#&uGD^q5H!ROQkRI>)&o;Y}98v$0c0wd?!Ip(^)q8_6>i( zVtAm9<$BrtxCnjD19d0hoNekQ`W*?uJ3_%bK))j{?k*B)$w_;}w#s&O*y^j(yeg6O z&)q+D-^?v%{~@KnIzrTP{o&)~H!s<>OwG^07%2JPX?w8j{P8zi*X}(1=I3sH0G{eHoNF>+bth*g1{aoytxKmKZikf-NR-E+%B9N@a+O&TzgLp zCG6-aI~6h#k(?LQYc-z;Iz=sYz*)N-R_AWHqt^}iuF+cX0Q(Y~1aL*I?uV46X8JYD zkaFAJ>vr${c;!y$rp6dMM~<^J(okxEJ>&e-YqtI6%WZ7>t!(O$=T~fgfXytsRp)TM zGU)id?8-vf4uW3KE;{~U@;it!t(VOyI@E#5ccEXkP9Jj1j)66^;_#AJjJ0^hdJJcF zMYJ4u{D6E@5E`xJ7|XrR*(AGG<80r!9@;O~M88@IUF1)S6uG@?m)$ck_yGALDY&C` zWD9B|la%esVA0N#d1-a!w{ERTlguFr*%nCK&e;wK=vE1*T5vu3;*MXn%hs?{b$pw9 zzEyF9g0(OF+3k?qqn)#b=|;tQx*F}691kjvH#gu|va7{1Y0^3tIDS7lS=n`pn#EDy zE0EKH@2c?;lnisp-}UG|C#aXXDa|$|&F)Vm&3-8>XDc#gQQbtW1h6ya6m_{x5j?JATgD0Ir%zkesQ1SD6 zlh(-u0%waPtv=7=lHLL3?B=jeF^rt7fmwQd-}ANkuQGosO)MyQ)uM~T$}aDv&G$%E zAel_WPSg%gp-S45vYF`Tl}y(*kg2og9;npHq*(Q(T_d*SU(*`dj;|e@O_f{?UTuHY zNLS%&E}aOp9K~kjbk%*I4gs}CiOtgq!olo+^hZ114JV7IqHV-?hRS5QaQ|?Mhs3Vh zS&)l)3k{g+R!6*3+9_%OXX~kXVSa>!fKyjkIgSWGCxYms_>6 z&2daw1+P-^s)2>G((026B5yfHKWU$zmuOL5HA`wq@(y*5qvo%Q)0S~K;mD?)(_n`E zm0CDk5V2EjdSbU3Y}jtaW^=^mWWDCnX<<2HXRw@6I>$r^CxtvfW|c7=#V5%oHLGbg zZ0kg~-Dg{MSFoGp)jBuD6Z_nFe%kTzsE@0v}) zY+!Zz!*#?)T^>byiYtz(rP&>7=1av%3xRRI4>+`bX`f4(m(>*iyIax*nL`B1)!`mt z4a5(a@hQj8hlU=Z7KKN;vdgq@tkf;Euu>zH#Pd}+;SC-4T(yq#8%$l@r)0h5LS+S= z6P#VCIJ#m6ab9wJ=d8aaUZE%Id4^u18=PX~8DM`5Am$0rtJ#gW0=QE}Bxns#)bG`K z&!}pk6_9LFTAksB#xOPcq~HZm1fX4Np~i#1z^-XuDI`YW=UpaQ=}c(82jB$2y(WUR zAe!&j2%j?%qEmGc2x%?dg64M4Zn_}5WYd;w5q%=oKE~Oc0@iwGRTwWiLlEGu7J@{` z_}XJmB*!2?WkW3@JDHaBon1V$lf-zKc!Cg4v|W@YSt5IJ>4%mvWKC zv1Je;=eL{FIiQ5;j1;d=93@S743u07?fpWDuH0oyUl+T)GLC9&T?^BVN|tGIm)EB? zH2t2|QypI;bn}oaHWJko^pONQetzCW=xK)Vj6mRQ*951E02ne2*ug1^i_M>EdP|k6 z)hzpPGYi}ir#zP5W{N144Kc<5&H%*b@C_j%z=Hq}(Q(k2^bV7>R1asyHq(+FF&heO z@J~%8uL zCkJ-y;(o)?VR(78dA`ajab~rQ8|pNu4_4gRP2>Y5=J5%NX}Vv&+ZnRyhT1(=wJUDH zloiw;O6lfZ!4%+$Y=mb80%zj3-OAn+h9KZ=?oP|aic#@Nyi@1|d}3x3L9npvQ|Nm- z<@$R)pKkLbE@fq+GaX_7s}y+86@j-1jgN?opH1<}?C?`rVTL<&lu}R>bb&)6_GS|j zU}NZ#5a10GV0|P&z{!a!7RlRV7fMHJL0*66j|@>fMInlA2|^FC>26a?2?p}#iTs)r zd7|UcwW{D8b!!gNSNYBPjWRHgw`+BaYqB|ODLZs=4&ViVPmXk6gbCjVk(U}#ntB(_ zWnDCvPT#l3koU{$uYOA4P@E}qMRRnsQd9eo)M}qop%a|KPH;-hsqH_+WNpMm*(0s6 z{j}DFxSUN>bTi21=C!E*?fH#@8bGERThS0%8{@}UV@pVr{uWn*q1ZsG+i0P4&G;pq z5^}r(kkD`LV=Kpha{el+CY2U6< zpw`uR1bc$SS)CFmT4B-h1JM^~vv5WzpGEhkex&Rv*KU_HBw;@kl0-}6?JT5^V&YB@ zDQBRz4Un8GQ*x%<5<|rT`bh>6az?biu931FjaC`@e+2MjfL8$0Rz#~*G`@bBg=AU- z{lCgUA_JiH*8pM<$yC&YwFz>+&0t4*MC&^M7pA9{meIvSy41~rpx=kp+5y5-J`DG0 zy@tnoc(!7I*x-!;7#fQk)+Z>Y5MXSL+w zZt_jKE67_~XSr;$|Bl9s*k77jh9W+im{NiL&&%3O-&a;?uae$}pWiYSwNoIdf@vaQ zK3@8w(G`!0(%Zn^!8jnyKhc0X?%Kpqaz1fUk4(*bgMqjz<_!(1+&ImR_*p;9V)t%M#Kf2>V z&5x$g7o2u^$;iX@i(8kjD`C)$i9snT<>A8Fh79Ay^`|b{y-KN6Z%MRd>q#U!u_@bE^Y_>L?sMaXmtwNfdEzW8dtkQPVS7Vr9 zv0{9I0bCuy4~V1k0|uQ4y0t4QmQvtLQlx83put?0s6nh zF}nhNm}-F|s%R3HpJmnfnnqnp`O{>av;j_&xO=ffLhUF_$wFEWB-ROVYa=A8 zI-_eZz`jf*C^S#g6D4J(P*=TRu!?R#ORi8dO1#~wiPHIWHAQNl&Wo^7O>KHOF4Q5I zEE03tLPF%W0_e;)I#-Yc+l_^imY~Zcp+@C8kZ-R-rc{1y+^OvuV|Rksi7lt$gvnJ# z$3hOBMY~2hr+oOE)@xMO)2}ubXN?K@M@6FWMZ;XYM4$yYI=0Emi=o?uhSt$Ki@FTA z{~ZY}o+dVTdpw1tqaBWahxp8Ird&z%Q`u>fU$2@bdN^T)aki@z2bi>r)|EP*DJOG? zGH~=vuqu=0c=2ZP8Wxjx~ueuxGqZJfsl$XQc_(-67KGj>P9`asuo#=4YznoK>o$2EB<|v>p6iDk1Ds7p z&XrJnwmeE>sgsH}i6Gxosd16cJ@e+m*LHvJx%cVbIa(X#Y>I>TPjyh7MbkJZa_x9f zn0r0s!sNpt{Jh!}0~?CW7~l+M;tXDBB4{~fu(1SKOHBkBqNDj5fNKGkn+Rvo(hh)w zkgWuWQMfw;A#YGn&*6Y2VhRy%=>rCadrMP@5Uw*Q$b_+wAwsy`M40f)HE`@ODTtFq zun>9bO+eUeA~+dB#-4(m*9h_{7=FeOUduqZ(O{8!CkFi8A%fgF(R4EwLA0f!P;qfi zL$ZZ>WCaEy>mvNee6*zAMgidv0M;Ti5!9@H9U%7TBl4&L^c_nfL~jzrbAda7 z@M*ufcpglJKZx9suzoB)eli206dDU&UC2QAv}Yk-jzEwqz<8>T5OlbSS*+Hxh!A2g zI_}j77xv@>Wa9p0m%@Cf|2v6bbX@Hoq!~rSRW`yueXl`tWuZkV=ISl+ZfXKgg;VXJhnks3d z`@1HUHw2Y)Xnz6VMF5iuShZA84!NUgAIsgy!>U`*##fR_ML32vHQO9i#oRM3jx zEm5M%EyVpPz|R0)0Z5pIs<3Fil32?ctDNo}T>Y7mHM*yvtF@b%#;+6Xi(HPra&7n-+Xi&)!J z2sfq?;?vaIVWUEsxYvnkB2Uz?l7_zd01Ln|rb&^M5fpT_C%42DaxsPogk_*0l0~um zu*l5BDa2W{P%i@I6#&RGkAM6Lv$X9Ul~=sW_T)4=F#AxDfcGH;8o QaTB{hI9?O{?i{WCAE~V?>i_@% literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.BadCredentialsException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.BadCredentialsException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7e447f50ac0cd07ddc6ccea49fe7a6725ea3b1db GIT binary patch literal 16758 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 X95Lp|ye+=QP3!{TxG(74J?j4-vVbQ} literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.CredentialsExpiredException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.CredentialsExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..32623133d13c2049c084db3ac236a30c4635d3ee GIT binary patch literal 16843 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 Hsn-7hYZ_67 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.DisabledException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.DisabledException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d98805575991ad7214f2873ac3af498112fbc25d GIT binary patch literal 16833 zcmeHNYm8l072bFHE|fy)lNM^rr3EWzTKa%81v*TJwlIA#GcAIOp5A-r&S~$x=W@=z z(`hyQ5R5@15J4p%sF6o78U=}BG-`}BK7RO!CdL=W#E@wCw zUQ_xNSNcKI+2cptN zT=~X#p8fNKFa1#=+&Lw}N)UQZe~LqcXU*)}H~;Ot+Gvj`4T)vxWej`ww7p15am^6n z@69Z}H(q=%@b{+i_t7dZIqpulPTg(RoMBpk-|!68r#?7$@4{{O{atZ?aRO){e)am= z8!zcw^Wz-E=y({Mgm8cNlkFRKo_zTiv&8HnF{k3TBTtHDL%`JwqP+&PZ%8bvdeZgl z2fQe9YXrB%f*X-gYTx_B!brN66QiM9A&AS~mja0g2J2pf6iq0XM(tKBB!rflBPlLa z)7sLn_YV1y?3-*w_lSGNY&7S$+F^`YNru#_NyeCaZh7~vU9Yd-iIum65KoiwtxhDA zo8T@u^Z14xfBsmHn18dFI~IfuSMC=J>weQa*lry2!XdG^Qg@?hC~&J@c#v!ttjr%0 z7gRkOz~Tomu6yT?`E}2NTG;U9cu-CC1l4v5W>JHCj(TB4#?FW)TO}b%-<4vP+iFR% zcS;K#;e9otchdmblSVb-g}z(&Peb9OWQ!!=-tK`Nh>cWIcN@p5Zkg0eJG8w0x|UMO zV&YJ21Gg7RaUB@+n*`IW_yK)MFKoJXr{*=i(3L^xH2kRI?2Ui!@yP7aFU5*{r=~n# z&-QGJw`z(vcAz-!Hmh}#q;n+l!VxmEy6;sDiNj$~A)^D`%clm=JS-u5H?xPms9l#f zH#;;pyWSKx`xLKItSjV24{J^q5GQ#C?$Zox=)i#C{T8=E1}w$WOb=rRk~Q|a?qalP z)}y&xii>JWcizFE>K%3KZCfin4>PcU0rmXB04>4S#dIRjc4TMd4Yb3M4gu|> z*m-(UJX!pg{>bB9eY|=iaU-EORwvEH{==&tV6RGtJ8$M~G-0maoCr=Bqa^qB2)~uxwsr9d$YS;*6w-gKbU^(XE?3}yhT4%GfmCu32M7`%aqP{XYdEzA~ zf>NBPJ`!}0(;hT~3J1B@S@T$o_vdME=#Nc14M~dYMIo)R#He`_zyEK`t37O;V zmQSaJ= z!>cBi0rE%Dq%7e}dUaFn0O>Um2|A+`^#^S^IH@~m2V}dnR2TTMGHgjc#9C1(f%+$)%o1Q=ht?WOSQ`4CRl zngY1PVCVqwdj^n#W5~j_R=uba`fy4P)TUI1uRUf!ic32UX%ktM+6D=5`C5B9`!zHD z$%Zf|j+T6U42=5}+J}{Ky0+IHb6p$=>Nu+5x>n>nH81m&mp7+1B>h_>rwM$Wq??D@ zu?ed-qYq@j@$(}#z~FQMpJxCm`ewLP1i;{F)QwJ1Tx|c;%Ui8QtyejWn_1*fc=c1| zR4Ao{4K_}r`7oN)8a~Y|qWLJA`{+36j5>8OQ{s`rax-1&5v!rV2LJS8=DHyrNvX3{ zMf+W{wbNG0v@3onx8fyvDcTsTnF;urlHuhHAjNxUsOAy6>XQL`Zgrn!=uo^m+Jca- z*AqUn9ZuJ@|Me(QB!UBKnFr}a<=mLdI>@8-*z?Rq~!N9kPflUbm zkt8E(IK=OuTNyvpipu7*d}xf~DGE_cPZV2-OLv=AjxnG=L+Cf;&=Veyu2mK9u;22K zzAA4mZ&87Hy5ETVx$LSH@92F74PT?*JkS{q6P^dAub?TyH1|$g%azGm`oqvYg}h(c ze2q{7hvH0?E4sjRYcX9orldOTHRuGVuoIMQP12fr{zF7ICPcJ8@&emOd!5;pVxGoZ zfUdN(OZi`0-on_>6fK? z$4;`tlI;hi&yut7CMcgp_ofk~>?zmo)(e&?zQ&v+TjNX-&_7b_&W|w{fcA_MpX+mc z=FAdPc>{6cB`cn#Oz&F;sL0T0mtp+tXug4_gBCHQ1dXpBqREo8wSn;;6#$U}(EDRF z>_Z9#HDhT4-A@b1ksQ(cb2M*FPG@hgb%p7jt`-FSA+(k{<>PRV_G^5+$7d@hu!FZI zV16oY*p$JT15jZZb#ulsEh)5fUTs2mtRZew@=JXz1DuiNCm zXyB3+zB8o^LHrX<_d*5qYv-hyzptpf9K@rn4_}|L1+^1BlsDpnX(nMlRr;dS6_3&? zorX*tZFUv*#}3WF;0&*EIV!qNwz_zrnE1~$aVwK#F8y`4-K>mLo*nNEoIysfF0zzq zJVa?6y0Gae`(0Cv78B-k7Y?s9AI$>rkrIo^2zCPKW7ZQ4N!?jr|C2i&#Qb0meECUV zj++FaR~_M7m#HgZ()F21_?hBT9WGLAE>K=te)^(4q=icLmP}8voQ@a{P!=m)oa3OE z0gBT$Sq|b7R>H)Jq;M5?7W1)Dli5D)LXAY}ZWZH{VpUN$lgjJOT#ccERhsa@X$f;( zu;t3}{<>dla%E)PtDLadFgzgFc+HI9jZ|v3^Vq=5QBwk&rAzQLWgkjA7+a2JMGAmc zN6=E-gQe9%mtG+_Zp%-Kn3D2^kt1oJ(IQke&+N`yk5FyzurBQ(J;KW|uNBHVt4fEg z8T9Bm6G~-ReR-PsS~bhKP8LOJG_eSB?s4^k~~ zLKjWq^0TTMU)pI%3xA%9lQzR>GS@0`fW_`W0BmEsi-0x(NZgEO08J4PRh==k7tOvx zAPBTf%j1%=7O1aZFgR5|qAgb$w@SS97>~OsoljR&r1t5&h&%Pt=Ew758G^`4Uek7B zqJ%@SWXcQ}Tt^&SYi*P~2Lk~yHL3Q2dV3WUrSfa%L8H$Ux%U$}b~zmvOr|n=3zJaq?4=qlQ0$&h9CKP9I5 zY2x%|kLQ$hw8QZ4;Lq|_%9SKPwVq~$?WV1w`!iaY!d>MkK&5+VU+LqSaxw=f14qvU zn<{CJ7jHJL8ZQ=xSz_xqjuqx`(^P|aNWuAMEeDbzyi(#=HE&djs#l$UHc%7UC~-(} zNnyXyR*IX`MDRAtIHx8!aw?KuqaP2=)H?-s-O6NR>KmsA(khxw#WZt~f@t=!XbwSc zhtb>~3l+!dAoU>JyM0oDQvjSo$N=fZ>K1KzUAdv42QhDhd^6=QJca z=tou{!=`f^zU)U!`fU`t52C?dOabUuP3XQI%`lqOqmRU*_y%w^2avo;crV88MDupP zxlk`tK$#UkhObn7{1|#zn+bp)D+?A?DFAr8SHV#cGZ}!JsYIOs++(le3bTp?AoZf- zY(4n^oe4B2(M;MrOq>7vtzk03aIcNwfdT+?%0XF!(*c}IlnQ?1&iJfMOeOU zWBE2?c?MWISAV-ITXu!1E1+)3byZ5CIxrUYO*EXa;?v2N5ebs2yBPnL0eTK!8KADp zJ7*7wDz{*QLn96xUMS#+s<7yNC)e+~vVwDR!V40Z%JXP=Bm94D{GF~Ac-|1Q&iLjh2hA)9-&i*=>_873Nofw6xjBHJ8GsI@IQICAp##8-Yjt2`k?qW~)j0qx zwgIl6j!EMVOGpD16w11+q+#-MH0fFmB)QS>V5&W()i#spR-(QX7&uv!x(}a?dJ!-q z%T$7Cl*%!E;xAQ;!Qcja@NRgy5)w;lrpYd0rb?&c#3;Q7jTuz64Ro1WLuoVp%muh_ zdqDy`b*L3gQ%Jx}*i)$wO(yM+t{c$YNKKMJGMS~)ZkFR!0O?QV-qACF2C;vV359s? z=Q(@L;67V1ZzazSj6-M+P?PL?&^*mF4`J{y8j}XbU>7-J%o#<4jgu?~8-cT4><|)w MJ6cTd&dJvQ0GMJ<0RR91 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c642f5868bddd2a0de35f10acb5d36440e8ce662 GIT binary patch literal 16770 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5f7b7e17458313f5e2d5aca60b7c352516ab56fa GIT binary patch literal 16862 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.LockedException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.LockedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9cd1b8f9edd1c5472f8ce97ba007d2102e53e15d GIT binary patch literal 16831 zcmeHNYm6L65$-*|O&lkVUx}TVI2${`WX_HqCyt%q%lTqEIX`lDcE}UPvvYf6@9u17 zde3Kr_(6hDKtRM>f$$J{Cdpu)AZYrA>X+U#fA8XL5C27Re@O~xAb$16x?3;X zx%Q_8h_Q(%Jn0^5_`m+y4I6iyeDRla#N1&q&vQGmFU5*s;OYm_egnC4SS+de(hV91 z{5W>&1h>qB8oZ;)?q+Aj!Z`!*7zB3FY#*({4wE&{A_O#YJjb zM+S}l;UJbfr`qvD;satXnhV;UD8Z~GLu%C|6U=?Lzhl>~H`edK%G*MSC&~2Iq!KDj za2K6!j|KZ?oN8PQa`B1GlKQp|DNZ7KFn zYoVjOt48%+8YFwts7C!La2vsCD13};kp$e|JFo+>kxCkF^H|NTl6q->R=00yE0ruI z4#hTbd$ANZfx)0fFfA_#=}Y=i%WXJyzvV}+3?ru*#GbP^`MJj@vq!%atBReP@en#_jMHik1 z+QI&2yFr50U&b`H+i0FQ61fRqJEWMes9HdMzcWC~@O25D2(%s98To^qD566^`zUsv zew<7e|Diwfc-I}Tok-nCb- z9>3w&$(^<8Sww36S57x$H&R7~zCwW_F);*)%rUe$s&+`3=0DJ70^qz6hV4c^O$I>Tsi!VOwg z@EE6CDP?p=z}o@gbOXx5oniRtib zsbzrtQ8XD#_^MvrbUQ%$EkuIO7)AYIM-ENt4%z|vE-lqXL81&>lAmW3}OzuO z1Qgmw-UMCR8;-dy4u%aJ)o@*_ik+I51}M_s?F%5IdJ@Z zzYQ=n6TlZ4K&s3{?r@!MsR)3<)0i8dpt#unsh77#i(0R81UIudnDiT`s+mwq2^(yj zM)N*2nKgWpSw!i(n_Ue^*q_EsfPkO{^D6qjly_orKL`PEQY*o>Ik8JI* z*_v_1pD3(&Sy75M##(Lyer9BN6$41|?pa#&C|&i*fPJ^N&oXo=MAz%d0NDd%N@l8nx0@}8BTE{y^$0ylAmI>%&SmVQj{p#Zw`$EC=Zx187%})lDl}XQZg#F*4 zzFa39FwMV*)^bg{mVqd8Pa*GDHD9BYz@a!( z<%%ve-C9f+jVq~+_)R*&DeMF#Ta&b=zJC#sjVTeWkD|c#(OzeErC6ZxmY}OF?@|6Y zR<|%VG-Zn?MPg`r37tEjIe*HE!4hn&#BKG^xn})RMhRx0Lz9zlJ{2wf&AA;_WXrr8r+%^SjgWYF{&k{RV7uZR6Si1dy z^l5Sy{v_qI=-xDnls)Cz-A2hW#W$IgbZeX`1Nv)*-GvF}641Ue;&Xk0&w^QEDsLc8 zyyV5Roauef0F@aU?J|si3(dFDbkQP)l%VnTV>Eekwl*;SlM*0O0D6ClhJ8q>pk^&i zp!<0VIg%rKe}U%gS{sIA3p1RZNYqM{E)^#;EzI92h=qV|Wxj%p`w(1V2A&13YE`QXW2L1I)-nK28S0$7~F> z5)wvGbSln!o!pPA9dejtPFBogFH!I}P}sEw?WgedX}T+@TiQUQVUz!gflF8T)|4^? z@i#QR3l-3RKQGPVeMQ~nARc9X`1*`3s2%8`yb%{nXK|LN>-#zU0Gp$nUivfn<< zXgOg%cj53V3(+hB9~rTjj9@o_oy>ZQA+0;>>wkL3gP1>F0AG1BkP}uOc9d^jrmloZ zH|HkdXNF64xJa?NM0r{H>5KNT7An%aDHE&G z!d22)&c{Yg=7t#;Y9vZ`s|2SMmzH%isiNM@)fg(cR1-cpBVn!!wp}?f&(U<5BfK2*TA`}5s&vSjL7$#8p;U&|S7(^7 zRkMQYWO1BDlZXHd@DNK^)}x`C|6(K|;<&nbvnkL3=s{W~7fjCaDmB%)v7~aot`>ma zyNDha0%oQ++M#5D5s{If6l=STB$iOQHlf%@1?Ybh#qtXDL8=8#>Y_ZL7A<|Q%&k=4AW8;FSt4#kQoGhpya;^0PW zqZBz942h{JwGY(WtAr?(U%L+)eP+nrPvqF;bX_o+%G9ZZ!a&V!Q_iWH{HFbymi5f5 zjZ4esB=plFQSzc;8D1jL2An!|y;J3>+gU=_(mqRvEVKVPG0jgCXEu90rlg}ChJQDI zR<}~FB>k!NG$-n`Y!y9{)50|Fsz3oM-9!6IAJ3GNIY1dWdM4OXNprk-vuV|Nu`tXE zTfcFvFo${@5af0k&0UF5ahwiO55nD> zwFr7(dM}?$iZRxhSds5aq*58OY2CrJz`_`sBT~#o&XqtSu`W$x>640_L|h$ewk4-? zPrtb8`CZR^=?`@8oN7-=G0(^Qrw%YKp=CVDxpq7#tZ>$eug-{&1V>2AZ8o-{n*neJ z3qFHa+W>}7!3X#nK&`a_REUo5E6}V%^L876?;T762ch6gM+U>a=*|ILZDG*Q;Q+;v z);0Jt2MiSVlEIJyY_c$@#2J%F0WuHMX8m#v6wNUX9@HB(bYG8VE1GRK4?cQwJY?#Z zoY-Rk^%M;7830Zp(|KzUAdv42QiDhd_n<}@TZ=tou{!=`g5zU)U! z`fU`t52C?d%mC!ok=t&(M;Jq z%$Was)i9Z2_<)V!(Gmc2%0XE}GXb1WlnQ?1&iQfNer_p4RPOlqDcB!JjG82F* zvjggJG+#iIQ5GMN%tH$BM51oE!|xzW5MM^~6*Rn=?P~^9UWVmsHkKC{%Tqwmz53fz z*|H~0JpuJXuBTE8)q%0F@1o&^6`xMFj7X4F-NpF#4A3+9$^rFM-Z^(bRJjEcKS0BQ z!*eA(Q56=wZ{_-3PgZbVPIy5AQ+XB*Z-oD^jlb2^0?!*k);a(E$Hemjpk4xyIRVbs zHPvZcGlEJBi$+l7z^SeYi1QUUSk)&=gf-hL@p);IIdLF(cG84CW(*}&{gOmp=|eLI z!Z+3p4BOEIM^c%GW_|(SWdqQq6vrN)F?0c#b*&DJEU}$gzB&hhr8dCLGcjr0VFhWR zl0sRJl{8FVi6&dCfh0E?9!#~Tvc_f--AdG#0|O_EGWX$gQ7-~!WSJ^3jY>74PyA(S zF&Nxn4?YMlS3zP)%{191%v9-AoEVjNqA`Q2wt+5FYp86dpM?PTO)p4*r!KXE843xQ z345xbgq*E1+|NR~1^u^DlO~W%W~s89L9PYJKqmK&o(~Jy(H2Azq7|S56%>$KUgA+f5&gkK6%A1F2PBXX5)UDvN)`O#A5shF%xh;K*S>E0 zulUD!@66eAzVnzfXJ+<0{~~MRh>QkN-HOA=_3JZ{-J}1fZ^)wdZZiv;Dd?*#ecC zR7-v4q3%=b4nF!1f&Lu{p{Drl>pR|e-O%+f=P0HcQE<_o_UIped1%kEi!c6W6zb4`f?BF4sI^iw>zlmi z0*zt_PR?i{ED=(AiIG)y7&3Bd$q=pb`B0U!U>E{QvZ~U^wLSL|dVC6k5iC5=IkAOi z1D|+ybGl}i!M`xG%7^!dAy;+-AS4G7Z66~?5uob>jqkVtJTV&iwrAC;Pa~TJk=1l# z$2z5cj!=ku>}O<4zEeu>m2Xp1;+<0B``Sos*nZ6eOIqh+8dV|6JeStA2uKMIL>TaDHmK1Hw%0Pf()A>#XQUmBF%=r4ejTP3z{vDS zCD$t{SqbDP8qsci+QZ1ziuPPE8<^m~o+ou8YBM@9JxiUG|6a_H;?MV(yk;{5jBFLW zCWC+peq%D&&DSdYH3+gcZW+aFrrm$7`BPeAvlI9=7gsCWI|l7~D4slNtX?Mng+Iu6x6an)k~9+084ouE+p|D8(>YonZCWG!DfvUDtc@<4ZTT*-(tR!SBo8waRS1IY>5|VJuhRkUQ!~6<8jBHNC$v&;vU4|HPT#7l6 zh?#ALF02+7<(a{v3$Tvy@=bso1GkEL4hocPm(;2!#I#OprX-aZCp(ao$l!AstHdB0 zZrHA0hCJlfc%&pmjO<8$WZ%$wPnu|M%{x-*9okUH##SY&x3D-GhDw!5sklsSFCLJZ zZ|5s50><@yio*PbJePAX;bl}GBlmV>4R8mql>PcB_XgGvsPP<)%F5C6&?D)NXruGosnusvQ#8$ zJyn$G4q8hh1I3@mCKU-^liDpc0~qzO611kE>lOS1Dr;#9UrQ5L^ z;`O~(z3tM}Qp-u)nZ@or^%l#AO^CwS2xAeO zOW34z_zZ`L%}23$1eSyLtdE+kg?Sh;(o9EwL~Wq3!GBVjZac!m6O*~9_B(`i%zSfM zji1PA+@H6i$&qI^UIYsh;rl5Y-o!aF@_`k)xe8l-2w-a0P8)%aju%T?5W)6(-o@h% zt7BSa)3`O=bW=N#S0&5~D}-r=UwMSi*swz#S@i9u>zG)P`y)Bq{EiF7=BZ+WFLMG$ z_-?zC+@wknlx=3G9el>f`XoKbZGv)AZsSET_v;sN?CD(Sp9~^(z?ZD)SoZ$_3h#bi zc=OVDf*<+WP@k+sgOhfKL!AM696%TAZl8Gchq(o z6JcD|kL8IOsHdPr(LJ$>5F7S3VGbCwzYOem=hy=u3fn4&o^wNr$5-V8<$a{OL)nRvGCFnr2ZZcNgh+qn4R#vlI)}?hkK|jxuC%d3`yVOq+)SuchGjD$WI@T~mN_R}N<`Eb&!7fqq!P1cDKJ zf24_u0u5#vj(-oE?_={kHhC{%uP`(|{k(|C^ahT_nq$Wr(e99zP7DKj9MutzA9QaDc z4V8${hJuxT&8v`p#N{C`ll01poOqVVlp9=l`vl->=-Hqe?^{{`{P2sAHT!UYKSM%$GX8Xt%|KW0iJ8x{lVf3g?Hq z5ab^!TnPYqPqsZLUL2ES-GI8Lguf!SH%^lDrr)z$zSDqncKqPL8s%KXMix#QC*T+d zHf*xWe&-US#ae%x3x=lDgH12~Od-=Jg6#-~G8~e7XSw}P_IPOKPv^)tUvyc+IEStB zU6;OB!k2E#yp%&J78gba3-;h?`^k;=xHKx@3xwulD#W?mzF^85_R9h7GR*EMh+lsomsJ!3w))-x|O$t7{tYCgG7}~5+ z@!Y!4Z$=u_nKNK$40zVKe?|1#Dl=yC*v-K~Q`(9R$C`>_;T;^?gw1AXk}wDD$cJG~ zeHc}%M>c$gVA-LYTw*dfFN`e)^9+;_w|RPY-gzGG_Rh(xJv<)a>gcZ(%JNhd7Fj(= zV|5P2NO_s}rE50vd$KrAvr#5M1)LBS+ldX_`LDx6h&V0}4(baUBzh3EX^ZGzWm4p<(&X|{32j^dDRvi7HAV``!RBTn-LWWrCXH5F1Ubx10)vTK%a%Xz=*hNSU(M4dERQkM+CRdICK)5Q-wrm z&@!mUuau=hUHJurRdZvQa!$jz;vJD)aGVcYQ#{&-^+I(@)q2%?%7!RpE7$2DfG8cp zMxT7+;7&kr#F!{~1j7Mz%qzJ(!NhQ-bkToPIJ?oMY~O4 zb50o*ms4@a#mH^a1Ra1r#aAW)jC+i1%62KMltxThcY<`jRWDT$#}p&0@yr!SBC;bn i#*!-)B#F2@+6);#&b{>FmKTnH%D@w&*Yb literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6a1c85c45613b871c8e3815758e06a0cf6813f54 GIT binary patch literal 1200 zcmb7@zi$&U6vy9P0-@0K2M8pFGPQ^ST?A{Vw3If|K~d5OsYq1L-D~RR&OU61UO-f3 zVgm_;1VZo!AXfec1}0$UKcF)U1J9SzO8~X1htt`9e*S#l`})H!9McMFQnfvuC@$LT zip97kRmam9bQL!}k9Exk3c~|txD;L;V~ks z<_>tmA_J%WO?IDEA|~3E<<=$!W;Ru@coc+cOB=-k^B;h3?=NkO#c<4p!YY&p&@uGk zl$}cw#ZenL*9Yku9#!UL6cGvOoAsd-qG3GJ_h1{GG;ydx7cH}AL%lpyPd7y@L%z;g zD?*=Z^J{$O%Eup1CtPrRC`PnmU}E4J8)Ma8K0IB1&G|Xl`F!{1g)FHPSgJyr5Y(AG zOI0b>v)R+fU#DJwVs8uJ)S#&O156X@iL+I-Uph2*V4(x4Fl)H2QqODfIEipkF<~&Y z)y|glCR>$CMmXHnhOthXO%nqn^<{ryt=U+prZl z`cPIFOM}%gRH(Dgjgsv&{ZmhCp}l<60v+$i5!wD8IPcbo>*|4ASz)>w)t)!JCjI9G zrB#?@K_I)r+>~M=O}N5v6(;gEUj`k!bT*(J`G*(s8feI#ClaPL zJ<+}>np-SE&vs9wLxc3pD`X<|kJaB1L_Fb?e2; w-6wYn6lI-v{phut-nY-Zj1#7qkpuOkw0(zK4dv9p*h3*@^5~CL14XOyH(S7)F#rGn literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..daa0a4b41e2c6123fb4cbbd1c47deeb89956f501 GIT binary patch literal 534 zcmb7>Jx&8L5Jo49fFKkK3MgqPs5S?HCgLX`twcd2Bs%YU2u_@}@ywEhf}_wPAxaAF zLC+1i17o%zi4YR5Y|mJJ@0*uTSf&6cF7#9K!Ib^$phh@$VVDvYRWLkFRmC@0vMCfB zSEfBAmd4K9ZO;v{gnBg+NHSP20_yloSz_4C2I@|=tt$KN^L&5>?`NLbewihZwUZsfoy$j{MDuXIQD<@l1`O=@pU8Tg$d045f_!3+=PK Ab^rhX literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c54f152cfccd18910f7b07d723e685d9f72d7c9c GIT binary patch literal 1118 zcmb7D&uddL9RK#UvlH2Lf{F+AGQoqqg4cQJX05`*j&((-prmvI3Mkj z=cFQt>{c3`T}Itn1gHII$~6(sU=Iod1ND<2s&=e1gt|kJ{Q7cZPuAn*0E%r`nqk6X zMCSJjIdX=`E{>64vPGcb>`XJ8Dp4JcFC|rIaZBh!|VZVo6fuGwY7MMMDE8P z|KdP9I5mFfX6_s;c$+L@y>%p3stgNLjKD;cEDkxUavN3%r7D%~fs(a>=Ge6j=kl{i z(VjoLFcXW}(lV2zBmTGN?2J84=2Nq%Ckf1m;oigY$(#@^;6gsv5BI7i6BY9v?uTK& z(UrG9-+UakykiD#9{(oy{qj1DemwqrHGo0{1?s04GuK!0F58CrDZf8#zI(s_`cZL` zi@PV+de!H`hjzH35={(o%H;ZE-1;TldgANHH=llhVc6t}7OZZFbS(SQ*@(O`QY#rH frrKh5wi;3GNvm1g8aP;fDV5T%riM5uc`yC}AAy9X literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8dbfc337f644eb9f0a4a7ab6fef20c973fd13344 GIT binary patch literal 11700 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 as1`7OocqAbJuePC_sl!6@0<(fg8u@Z4z;@g literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f0763d490fabce1b15462c2ad95b6e04ae44f95f GIT binary patch literal 11789 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9977e555bbf9d12f284a3864512248c56a31d50c GIT binary patch literal 11774 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 A6951J literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9a132ba89879311a6173594945f785e90a316057 GIT binary patch literal 11704 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4fc6aa88bfb0a32e67258a9605f5a86c8a16c87a GIT binary patch literal 11707 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2f3e2c94c9505e99478048207510a3af8d9c664e GIT binary patch literal 11709 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..1524fa2be52ec91e6e9ae046842a9e872be2ad35 GIT binary patch literal 304 zcmZ4UmVvdnh`}enC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L-QL=g-wO-@cNE_MY;DVu)ZrN6>rH4_6vMG=E98Ac}+mlP!?m!Mh!Hv6Q) z^1qiFY=1(`*1=|Wa(-S(Y6Z}N1qC@!Cxf*nwY-k+a6kKyiGk6JfwLqtH?_DVF}DEd sMA59ovP8YolFS@EuuA`=tkmQZpI%NsiQL*1Agc-(7#OE53bCIL0B5OnWB>pF literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..945c17dd9916a57f8bbfdd367d8cc7a1453defa4 GIT binary patch literal 414 zcmZ4UmVvdnh#@?`C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L;*%qvMPN=z=vEK7Ankq<6SPEIW@b_J<=lBhIMBf`^}iGk6Ffjd1l52&Ri zHN~m2gh9|JE3qt5KPNFSUEet;vAEc}qKLtlbayx=6_b>qr@ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..65880d2f3b495fc0996cc3e40895946b73bbd111 GIT binary patch literal 296 zcmZ4UmVvdnh`}YlC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L;*$xqKOEeS47PEIW@b_EH!eYP+zP|euR#K2Hd#NbQ1k&a2lB}IwJC5|Ze zfz3Xtu>9|(2HT$yvvshUot&Rnl3G!s=U7mX19d7`Yf{VW_zw5851AMky%;!4GILXl xOA>PnfKC+6N-Rs%D=o>)(F3dWPs&P7F7fH*^pnV~T>-MHfPsN=+M*EqbpSM~ak>Bi literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d433e15704abccae09ca0cc0f736571bbac3c74c GIT binary patch literal 1205 zcmb7D&1(}u6rXHUW06)XRPmr*DtM3$c-2cj7DGmfX{}6*^;uYVBH@@Se7v z&~eta0tO-N!ZWTwFbYDeuuZ88AK+9vw7;V}T#?ZTWI#yYlIlEV>yBH6y|<`y*grn8 zdJvH_%<|a7qS665AGPToElR3d#cH$78QhAxo-qkZIE;6UZh#aZ>?owk-b{riZieY)GW_x6@0Eb$B9ddidw%5lYFcH- za^L0mhpl(-4_-fBnB?N_{93R3T=>uqHg#gCrJytVW88Xqw8InMm|cAO0R~}BBu4Uz sr3(1yOOINl#v--6)pDvWW@oz^m7msYW>7BuGL(RbkCd_8hz~b7iTCrQ2+n{ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..638e87f4f382769600de8bcd527181f5fee8fd72 GIT binary patch literal 11326 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c18423dae2bf09764e5bde98413c2c59e2dca5c4 GIT binary patch literal 314 zcmZ4UmVvdnh#@q;C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj_!F|k-LwG1et=LKXsqR0l9CMTyB7rTO_<+;vr|42P&%EZ7>QN-X!H9NqD*NH{H z40-%44`R3uHp7$i^GZ@HO7t8H3UZ*12Ww4gc^%*3e)b^~1EUuMXGvymYH>+oZUNAZ rqFIS$iF&0anK^o3mHtUtsmUciy_|j$xwR`mRuwQXFiu+(Vt)+)9tC&y literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.InvalidOneTimeTokenException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.InvalidOneTimeTokenException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6428d89bbbccc4ddccde8611ee91ccc5c6defbf9 GIT binary patch literal 11220 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2f775464d34d123590c04d3624deb825f7034a42 GIT binary patch literal 699 zcmb7CF;5#Y82#=N3MHaNfRIoH6I30liOo_EFXbu8X5{_GPMlf79{758tXAvZ${kLS7#HRMPQc4k&*t~lxe6RK=t0f=57|-) z-{mY47;-~TpBEPI9xldx@IojHdqObYH^yO{+wX7F^~TIB!|9)$e{%(?7dutuJhh@G zdn`4r*^y(<&;HI{{$^Jt@YbPh_%Y@w*wrq(Z|)vf?9;XX#@)u~Whb^U8cch&n~`G$ w@I_ICF^w%nSW6O(rijnA!`QtIc0F;!{X8Z3(8W>T9l=OuP)plQf}x@>&;9@O)c^nh literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..edee78ff8baceb658e80513e755f380f05a4ced9 GIT binary patch literal 16772 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 F008nhjrITl literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDecision.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDecision.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3992b0122aacc8328aaffd7c7538c96b3352f4fe GIT binary patch literal 96 zcmZ4UmVvdnh`}MhC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3zbLaRu_QA; oPtOsV=aQP7Sqv1tZ1pggBe9c#iGeYSfjzw_F|Q;wrJ{fl03x|0OaK4? literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6ab17b8908a50c4869612a85b4fa5e81a86ca1f8 GIT binary patch literal 11307 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 JsKJZR{{a$M4441_ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..bd4515e70086d08072cb47850cbc8b1be4b542b1 GIT binary patch literal 1603 zcmb7EOK1~O6un8)rXlpJ6&32L6&EstF72itV^D^+bP~~6l$XhCeC_=D=1n`Tv{n)P zfE5%)5jUwys zGr}SP{n{*9AgV8zsm}PeAzP`s@46fPCefg0){ojqHe>YHn6BoSkxvIQ(=dp zfWyh1)-fDg&;XIknKf7;?(&_V*Y4%NZYCjd0WyMF)Dy&Vu}z9^KfYVFl+qq`Dqpv@Y$7w@soEZ3xYPVgdxI!p4F zB6ZPPDejotoTUr-ETFRlWTqyx+_j>fn+hcEURS#9^xhDB^jKYm&~MSmbP0NhVK}}m z#vMBsxD4G@g6=4$ImVm}^~HP_Pfb%>>h+%=x?)1Elc!sEue8Xw0yEC-pQ{0R zEkdEj9Lpt~2!}`fVcVJ)B!<2~K<5qHaom;0ssd7SOB_AC>*)Gbsz34dk+suVYB2dw VZJgP(+R1%DnQiM9BoN{rn!MS0Gv9pQ*V(sQQ0++=aAZ#N zTq*3_lw^56@5mX=wwx8atW~1K{=O#9y z00jws|5rGuc9{MRul!n5kof&RJ@Iln53PF73_l0p}r`qkWd`rVJUctCp0!ia)+MH|Wq z?6!Zou+7n4Sot*Z^LS7+ViIGA0@Yf>Dm_xN1*%@S`L+GoNA{u$A{Qa%iA7G9gUEc0 zesPlCJ&88aX63bj3&Ie2*W#ruKx`9v3!%Dbt(bJI9nLZo?HhEKg8Gpmy?=7l=pQK% z?pBxFc4mJFK6#t}%#*G2Jm|D3qx1U1e%5w@I&m z{Low>l))7mq0TK?oUkYGOt8rM!5N)_56;sW>JX~7-5gkNrTyWT2hUeVX$#Q(INodt zZ>A;Zn6>eA_|fC7)vHysD=_22!MW=AD^#D8cbR0$ks*Irw&(@I&{j~;blr9wcd0z8 tf*4JSt-JSZUHU7Pz8$5O#nX9i3R+a_XE*b8>@J{j$DlS>{FWeVe*nSETqXbj literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..92f6848e4d230927ed23f07c96f1321bf180c7db GIT binary patch literal 1454 zcma)6Ic(HG6#aYTgd8L&kb+d{Pna>6Hbi~z7$3|Fvi8;0vLhCi$lmX4S;UZTGdW;3O#B_(bd3{1T)npbU!>kwCrZA&Nw9IprdXbw+z@p{~iiqbE%-ON~EN0M<4ba zhnpk;Qf;xgVzz@N^;{=%3s{i~d_a{C&>1vZszpoX;H+EpEPLK&IfomzRKL3RAAR=i zc6S_N1|%IEQP5qtE!EKJhyD#0ZPR}auCHGHF%W{r%&V{r$-qZay%9=U2v#BVVCDV3 zd#~C31jMqCl=d}_2f(MCq<27zcjD6VZRIcX+{V;gb6d@q7UfH;#AN+i4ZZ!_g z2DCGU(aMz+8QoQ<_yy*p!##DuKq@0l@kV24gpy!-uHu0rraefV+RC(j<|sI|Mf@9) z_4GQA$@QfO+Yz2&On61whroLc=nMyEu`!+6XlUy|WNQ=xIXGJMRRxc8>BR0EbDzGv zjia5Eg3hR%a0&}6vGbQye}bmVtpKsR4`xnI1z5Q&svKvsfLKi}A78%eyYemp@iAz3 zJZ6nyn|UG&ZK{AC7Cgra{4-}mlY!8no4yGxwYgo5dT4*^LEe4+`KEpJ@aZGiwGG~_ z>E7!LFQ{Y$Lvh^vOn8xm;X&2HsVR7%Q6n=J`Iu681|AH!LPbmdac149M6(7J&oz!BXQ4$N)NR;vJG~Q&rGo2kL zYYK;;AyEvOZO0~ZA1!l4p3ggBt87Ya872TmNIXE=bwd$X~3owg}^u)MQx-hA(S z-}mOrJ1`n4m=kKnilp+xmGg>q_=ZqxR>a+|@^#O0S!A)UZu3z4F4MjUtyvaThgO!w z8V|ud`5+IYbtta!-f0%K9VoFV;)?cZIO^b0Hj`X&VPj(34SdXNud~4SOm4f{kFGfI zkgK>y=dvKuu*X?t>&y;VxMH7at#VgmNQq#(zGT4#xCnXN)5X(Ham{?%Q!xi_tIh7$ zX1hXhn>KjK2D_1NuEYxFcVuQ8E7ew{6?64HsQKxOCoYEbUO5jVO_<2+;~pZWcY$2{ z91%|^Rd%%>*s~%CuuP;5D=lteGQ8m2PGPz+Uj^ug)UV-B2z&0DYib;u;mxrAyomI!KZnx(1~>rwXj z(vJtPf6qQ1fm|I5k^csdC8{O2QJ`PkbaF?csZBUoMs5uH^=$wv4eds_F*0s-2U#38c5H^_Z*4slt8D>005VqzF8HH9c`({ReuUcHoi@vJ^DLZ3IrP;(!Cx_n|fMuK;zkuHeok&UC|Bo%Ob4B(#IR42~+8sBakRu+Ml^gvY|yD(ww|&4rl$c#ObOTlUtxo znfOkyGG*uR!Fmp-g32m2JCrfs=E3)GzxUB*g9JEnMCSwidH$x%hTm4cs6euBmeeyq2XVJC* literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d3e96900c7f1747ffbe780d473cc174af7e78880 GIT binary patch literal 552 zcmaKpu}%U(5QfJyXw;yIg_brJR>uQiL(rhfB^HpF*pR*50T-6rb9aElf=976F_sp- zhrMs$J2(r495HM)oB99b`~P|Wfr@v~wyq!h-07^}b7F*3>xQvMId+<6u@pWQV|v7l zv=pRm7B_`&qnl`n9W94QjncYfhnT_QMJ9qMfdlDK1-~$!;5ZqGiKrQo^=o(O043EE z*w+g|Popa<+7!6zg@e{c%r(SD>d6WDAKKU3#XM`N!w9w?pt|Bi#i-$LIk-kfJz1iT zNt;^J8pEudpK*5;lF-IK!5p@V9Js}^kSY$+_)qH3uSYq}67A{v^Yr8L_2oMPD00@{ zY>YF-biMU^Ov^=IEg4ExR~?QlVM8g0eu2mR?|GgX{8k0tsK^O+mO5J55mdsRIQCJO MkKXkp2n{>CziCXvjsO4v literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..a38371d3694f7c930f9730f0d58fff78b36c6f81 GIT binary patch literal 11073 zcmeHNYiu1y6&^dO*_&yE}9CJic@0%$b?{{eQCS;)wMJQNxPE$n_gzk=^7Mf@s2uxzmbVF>N`4Kjt

Sk;zVjIreleXpAe#08{Jl?Rq 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e127f24499a37c695213fbe6f5f70f08cde69bc3 GIT binary patch literal 125 zcmZ4UmVvdnh`}kpC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm}XFR`>FBOlBS z&de>yNp&wu%qvMvafAsofB{nu69c0U14~hUPHG8*kWW@(S)zVUVqUs_a0$qC>xzOB N26mT#zyQ~9R{$woDro=! literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.SecurityContextImpl.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.SecurityContextImpl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b3a0dd59fc98a4603a814b617355af144704130e GIT binary patch literal 153 zcmZ4UmVvdnh`~0$C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm|sNaU5IR+Q)k zLq(k-e9zp190o98%3)$)^kLvjEG@}M%`3@FPAtg;s$nql0UEB4X1G4gaD9;B`i>}i ItSbr%0Ite6y8r+H literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.TransientSecurityContext.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.context.TransientSecurityContext.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5a4ccd07b4d0d97d12c13023f0eb3ea4b04079f6 GIT binary patch literal 1294 zcmb7E&ubGw6n^E==zAkwgOa=;@v zYuzw__(=z8NO_QFJ$ncH37=Vkyu z)|oM=Mr#tVt~y*MEYlv$_?owfB@2v&bKVZS$J~I)wp-oW;l3?-FiraUB4oi`*n=rl zsd5@d zYjMj&UycPtdf+E7gi zr@i)nxTMXcW!V3G`{(5tH02YkTl1qP=-#j688K;F@UBRfyM7n8F9=Sx9_HT$>CB;_c5Je0lz6zd?TmIzNLai^<8l z<{YcOzgmCs^6<&63|5g=H%_nBJY9>}s1?->nPyh$L_dTbWPvyoBMbQlQmOFaXjBVX Gn(_}s!NceP literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.AbstractSessionEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.AbstractSessionEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..13d48179c5d1f76d4822c689d81a26882fc06d01 GIT binary patch literal 198 zcmZ4UmVvdnh`}zuC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm|s$SW?+%+J$v zOe!uZN=z;ZhVWg>Qu9g{bozcjVqL(=#K2Hd#Gr%Cu;l!_lGKV4J;#EAoXq6J5};9F ztw}Af<2&5XK4fBG^kU#F$;?eHE=kNS02(8jl~|UjS6Y&pqX$;$pOlrFT;kKq=_ip} Ry8>iY0Rsc$v_&Bf+5o@|N#Xzi literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized new file mode 100644 index 0000000000000000000000000000000000000000..384fdd554571827283d481622a98093aa67c8f58 GIT binary patch literal 867 zcmb7C&ubGw6n;q~v1qGR6h!nO^(Gq-ieOJ|jT#8HWE+Ht%5?T6PCGlZ&b+i6M9D$$ zC@2-df5DSSj~?~pAK;(Rvsd3FjT=wFz3jf-Z@%~a*w06B!aKNQT`%&PQ>NE-BE#!*~*gR+}&%wo8=>O>l0E(8Ba;n>)KGM}T7mjpScIOhNW)o|V|h zLZFTUbrhpJeEjeSaz@{rZM*N$B}hVPAGP_pFj?)u zl91B&4Lz`?KDOI|v&Flnm3x?U;DY2J(2x?^PeZF{#EuRbof3U|W;twyp5V;bexH=C z#TdMw%!Kz`O7a|D!5q&)mf@mCGh642{ahcp59gu{t2O7wwfN<>No}IKDlB8Z;gxqk z-+mglIgZ@HjoD`ku1o7M{PE=X)iRWtP?7`}r=%7zE`!x970lZX!{%Qfx85Hfy?Hbj z`e4M}|IdGU?Kr8yhD|f!1lg%hLd_MfD1@;-n|zY`Ac|F*X}st7U&Q3^ilS_`TX9xT i@+O#XZ8qyq+i|^>6D+ezw6n>Wmr4>?Xk&4s-rm~?6VnQklEupG7QIsPCK?1oxCw1bpUHcuq2!X=H zf`kM@LSkcP;D0b7v9hvtX5~3)xG+U{v7i05=SvNPEh5&G&)YF`@ZfOmoua*n5>$rLA?tNQCjIlmcV(%JhsJgAv_|iB?I=1 zH4Bugd559cPGBYU?Z4hMo`0G##Q&;A9Z7zW)gEzszzfj17kao{}~ zyo&BU!p$Xs(w-~>L~nll`uw#dJThdhBx~TpoHMBix|c2Uo+8MO;Uz3l9mdiW z%cL%CM2qxXt(5N?rN}c1!*6wTZZg@Ep&9XwFTeZ#_S3jiBSRcqTl}Zu+T4Nhw9u z!gY!$n6a~%eCGNnPGxSD*mF#y$o{sd!X~+OXVlDZgq8L|(t6rSTkR5I^|?02zLMHMz7Xv!qflIlm}Xue3O|C?&Nd nF*B!FFBHgDaV#y#$Op+g=jRqA7A2PC7cqbVQw|dYLq!1qM=u~7 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.User.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.User.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4602e2af21ae90873442ad4f88438894da86f137 GIT binary patch literal 299 zcmYk1F;2rk5JksE5CljhNL*trAvy|B2*?mCjYWaGVLdoYmR++uCZ?g|2yhB|5O?AZ z?2-be8vQ@|^WXb7ta}Fs)-}SnPMPM`;XN&_TL@3GbBdpYw2nmQ$<@TDv=>)lhu=wc z3WEwpD5dQT ?Tji*(VECsMRxYBnFM~sd6>9(gbU+4gG}Q%cW5;tFzAEwzyTu(o zV%D+JSxJ0Uz-Eiyhjul?-pbTynylnlJ^Hbx2?P)D3~ApcNdkdy6mvw(5jpyK$oiVR oyuN*Y9IgTM?Q$o;43AG%Og+QKcyf_no-%Az=jHf%R!z(N2j4|t#{d8T literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5eb8b1c9b9e742a8114d1fee4a07053a851b2181 GIT binary patch literal 16762 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..51e783d58cf04c32fe63631115cce63f01a00412 GIT binary patch literal 96 zcmZ4UmVvdnh`~O;C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflCnd2!ub?15Co{QH uFCekF7$}_*0OmU9=am%Y=ct!j>38*Q=3!!BjAGzO2I|U8PRyw&U<3gFp(BI< literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cf7079ecb45727245afc3702b8eba9df05822c7b GIT binary patch literal 11328 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0726de84244e176e428f04798b96293347358aa5 GIT binary patch literal 506 zcmbV|u}T9$5QZnG(SX4s2-d0W_N)~V6OSMSFCWZ-osCt% zHk~ivL-+u`fR&A1+=PhHGSkic@bUdK`hdJfs7Z{7R>(!vLz=K_iC09kAVqElBo3(} zO39c91Ja;c+c<1Y*Cx|S3eBog7?kmA_38QU?Qze6 zR$)Df%*zxnumLzLJu)TG*gSGSh#KTG$=(w$hkGfVfc zrT2^3%@Fn%Z98kZmF~Fr4=+Urau-kt?2mXr<4oml$Kx>olvAAek3KiQRtoKR2Ov}S zytM&EcgTd zgFXMj7qHxEIH(#ig^suS=ZYq04wVYj zKLV8_L9;^TT^Fq-y(Mf<+Nvx=&lE{WR>-+`3g}OJTz?MuCj|Q#Tl@53a`&cbFVG2& zBA$aEIP0x4DoDIQ$M=}SqniSH89@YWQ%r3?^^h=pm5{iPPL~2l#NkWI&wXRTIw=Q*s+Q!W7PK>}9!RBCQTK3F^vhi38 z<|7jr+e6o|LTBol7SLb1Lx@^EBkYcRSoxD+X6s`}(*wPGIUjijB-C|RGZbot3u_k6 z%mK92(B_7wDb%#)foC`u0YHIoj39In_6M3BLfLFET>x%4-5!v)yJIUfZEtM$01TZ; zAHFqr0(~^*Q^WG0qUQ}w$n>VR?Q5ffKZ2f2doa{=Sk>+R97-3|W$zBgz} literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55d14042f2c3d4c17d85c2c718703974bc31c168 GIT binary patch literal 265 zcmYL^Jx&8L5QQhZ3rc8EXt{$|p-d|N3Z$iBg(A@ntZ^KSZN}qdX*dE`phbcXi3@NG z?!X6R WCk&hBpzj%mIgd?I8LG?n^x_w=^;F3K literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55dda6329e78274869028731f821a44a234b323b GIT binary patch literal 401 zcmYjNJ5Izf5S@hO-|+9~pv@kDY9UBOva*B-5b1_wHkftnU^{G<0*PZ#a00jo1s(U` z4mi67Ofj1G-qVznFY~fEPi}@F#N5TugdhZY?a`#K~E5ZecY`hF58L9Vf0%laNKjEKGj^ D2)BdN literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.Person.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.ldap.userdetails.Person.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7b55c61260f06aae38d4a480c4b5cc3db64b340f GIT binary patch literal 656 zcmb7>yK>V&6o!u#h1j7Wgv$&w@CtH6Mu^yG}Am%N9Fl&iUtDzW>K>*i{nV3R!xpmXw!gl2mvl%9xF)g zH40^cnoy>^6O>AD*gl6jup5Gta}5XKM{-H}ji#(0Ql;O8@VG#gOIm9xjNtG_zz8q< z3vI_4Nw1`r$RjiM6MO;3^iupbdZLkGeJ(ggO?8TLn{Fle|F>^w4oJ=ZqnrJMs%H1g z?{DBK$#co|_*0jO_o(YND{>0KSY)GTeg+WYFX?Xbn-cT@xxm6iHPH~5$TN9;>H^nWUt~G_< zfotnd2RZ<+{{p=FV_bb^-SDg%o-ZZ2wwAPCf4%wklYHNSP5`c=pRuhii!0aut%mL> zOO9vB@mfPK4*g|38O}EvcKrE9*|Cp|%-yP84SV5iIXj7uOf(p0(JCFAXyiwe%`7od rlmyvik(sW&52NXF9gkP326r_$vem_GK1|o9_x?1PXN&3kbQu2wBT&sC literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0edda9a5d7453aa85f5f1f2f9191fe01b693b047 GIT binary patch literal 16940 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClientId.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClientId.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4a34dc86a01a3af4ac942b92c584f2252230619e GIT binary patch literal 171 zcmZ4UmVvdnh`~9(C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVCo?s# zM9<$5!~+reMVVEpDb8SF&lCnQV9H@)VDe!QfhZ12P0uVYDM~EK%+K>oDPa)u$x19s z)Xz!GOV+HmAJd}Fy zsvuMl@hFIR6~&X{!GkCDpa}j4dhj3~6!E=H;-+bd1~R)lGw;3cecw0p_$zGlCFESW zr1_q-oux&|O1$FA70u^nS=y?qxvZ>;Bbq5}?kJ5u@M)V&*{-8y)3iuKG&$$4a0kL) zT*M)6zz{{b(!R#6@i5JKzGVAKhB-2pg5Ab4yUKLIoFzS{2*{`borK7=Jth>KG!UcS zf>Cc^)N2@Z)0JE=`&{ZZTzPyQ4J1srZLp=Kbb*kWYKx}cKRUeXOk2HiNX)~|rZ{dH z&|Pm*+1yt!Q0u6yY@v_4LU5D#!mc_ju9z)wOLNoN!ZPj{4ZIlYafry!C{&9={eyX@ zJV(f}y z>btjfe0uq6;PTr9#HXN3xXhYD_qj3yovJ9gUvz~Pc&AQ>OvEZX@EON{Ou-In&%urq zBM!gTU*FLUX!k9u&AIb zH=aE=xga^Se5$w)LDZ%yC?F4Lt_M-fv_(}0xwYg=wg|uot%&es9!BRB`>*( zr!5Pq3hN`lP9NX#xMeIV9t%7L+iUw&(;8YxHr+$VYztAIYKwA{V<-3`D+?7}Hxamv zekCBit(Qczg>zh?g;ONwU$>s&H7BFnC_WXAyEj{b7W-)!2mpKd4_jlkwF9@`-nzGz zM>B;Qbzf$o#fSOz&qwf9fXyDp_2&~e*6%!fdLn`AUZn>~NYzm$2v#2rgEZ_9 HOZEQ&L^vrA literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..44ddad76c51b67db06255b07ef427af7441e534c GIT binary patch literal 895 zcma)5ziSjh6rS6VyIf2#QSk>6i>QT=%t90kPta2g39O!YMl>imw>!C=-0aL|=54ZR zw9!8xML=w<6blQrv@v2OSZGSIun{W@3mXOX&7K$qiwx}U{CeN}zVE$#^qKTpLuRyT zQ=1y0+H-~_d`X)QwLHv>fMu##2Jr+9rQiyv7Ewsu4lYE|KSh#S~*pCS4tdcsi3lJ zBRmkQ!=ou?V+=U5cJAtsT>Fjzvt$bkLvC%uMBJdi!y7TbZ}(Q-y?D9v`r97jO_F}8 zSu}~RYBNo$5Tk#wmQkLbI9Yf*u+)d&A$-a}%6t(EZ&AqT2I}8Jn&_J3pcRt3x4*iw zaI>@G5icO6&c6mXTJtC#OHx{N@`m#i$V3c~9`k)0#ynw`>Xa)HQN_V8^7<_ncEXq` z#pQUn>yXL5|1&w0q_B)Et{mNQd-naOH&_yvqlabDCg?Xgj9sYTIkfiVc~OK4mpnn~ sf4Ek=Kg76*5L2+?pwCS$c6qsIGlR={5J0@*l6CK@#mZpGr=y(w0$8;%0ssI2 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9fef9750d708d6383e708f6542ef442eadcce889 GIT binary patch literal 2430 zcmbVOO>7%g5FXn}9VabKp-l)8(3S>T)b0uh2a=-V#4WXAViY$>L_m1nea>$3?A^Y7 zOEw%(kl+duQhMQrgoIF~N?bs_P}Eb!sV5KxP6%<~zyTo@sF-;hd+jt>hDaIj`{rK>g!kA=#4(y)Zf8_Mup+rqOTaJ`06 z#ziH5E;eeOtTTn%zbxI#e)`ko?KGrHFhtrO8ghA{V1H?qy}`^-xx##b`O}ev(_Nig zp5!fece?`pmlkR0TY@Z)d{=TCoeCDH1%5F^p9+TCoEDhk(0 znXXAT5vE)UT zW78(VXp(7@%oSs0Oml!dQRx(%{vU=YF4Cqtp6NNoj_mS8F0zx9GE;&!Fep4`pJSHtWD#=8kvwobVMqR%=QIp^i9Ilk|5*i@Agn6Lq9ktOnuT_6 zSs^l;4}Ng-{SP-6)5u8)CzG)L4T)rbYz8*Je(jHkVn8efBW-<@T*F?#Xm$k&{eLUI zS=##HaWq2ycff+@R}1fMUHanl$+&0sQr6oTq!i@hnRCjuBTD;CU%{SuOF4;bn`4T5s(+^BH5_3ArU$B&->3|(W> z?!!0%oUy6nPu(~&OI}^3GzA}Rot?a2pGBbeN3|SZZx20#UJ5<8L(=ihR;Qkzk-72Z z_+R!D@7W_!-FIakr*NI0Evf5942vu#8DEDkT^zSg2ZDaj*~bM0WzRmEX*!1 zR?aTa)#*pB1+jobk(=@<=u2)^!3Ygtz;9s(pm#tAUc(+%dv>PIn-i zi{DcLPAj-C?kQrUS!@J~HE5U(Xv*4oMJY|2kN~~2AV_uzQ~w=T8tn9fNb<)|f(~GJ<4H!3zdqt3g_;Byb3zBx{f(+W z8(MTVDsJ5u{CSD!a(frLV^Dq46HRax3|3~#FP>eNoY@-GXB7;^TkF`DJZgpYG(Alr c3tQg{9gI)uOlYX!IO|`w0$IafU91TH0a@e)SpWb4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4a1d8a385dbf79b62e3130dbc3f2d1770f6c6ec7 GIT binary patch literal 123 zcmZ4UmVvdnh`~0$C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z5y(uMHMz7Xv!qflKe4nV!$>bVzbIAD z5y;Fh%B)H($;{7lFG|cS38^edWdH-F93}=v9|qR4#GKO95(Xikti-ZJ{hY+Sbp7BG RklEH11tkou?yi1e?f_V!D6#+m literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f440703d99daea227994c12184af4d602a00dfb0 GIT binary patch literal 126 zcmZ4UmVvdnh`~9(C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD zIVUqUuf!230HiXL6H7Al^L$fFGV)UxzO=uHA6n@F3f3d}CMNm;h)RS(c@uylr+iJBCZEID~QtM=Q(oCG}tTS($ErNLP z;LVeQqBjK(dhzH%5Rc+P!GoR!=|RDRDB|CnO=3jQh0IRgoA=)LzW2@Ee-CX&LqX{| z*MwRGb0y8Hyr%Ry*KjY=0vBAxA}sg2p3>Ysz)LKWI6h=ecHsdEk0JLbDB2Stllw=% z+`j4FSWJUcfGk7Qq8K4J2ulkUHqUYq3Yj~?!odP8v8feR5!S!*5C4dgl6xprK*urx zfkIeb_e&Pc<)$cYFgF;71b>rF>)Nz#E6i*>5mc2gN`e(7r*a?f-ur={I)>AbDnP1w z9xg&E318L*-j<$8YdGd7S*%uC^MMomNhqJCH*+uw;$}&UF)Q^ zmwsIc4vTz3w7QjYNNcuWHYTrvF!=h;-p9|cw7(=6(~x2aebaxmHD0Vx*VI;|n-16Z z>o)p*@bcul#kCg>r2*oQN~RDtmk~p=CzlJgLJH=-%VSmzC3gdkIfAPq?Gb&BiHZm- zPVX4cN8!ZCz`&#)s>Iv2`Gg9bpjaZ{Jqd6WRqjr4eQoCQqcs~2KkT;EYCTjG+Fwn6 zx4lA)BppwM+*l^FkzISp?jU3|XFj=WG+3(J;VT)IMLZ8j z&^FIx#N&|W;Lt1KqOZ;r9KUhzXoIOPPYSvzvw~>pmHqjFO1?kuo2~tMQQ3~r84<3! z#xoUP@t6v4X-Vi`qHft&4a22pXFjj1YumH^q#J0mq@*3w|G(kM)jp(IK;p5N+TO^8 z!P4$;aCN43s;M=HP!0e0OOfRHJur7lSQY-A*HQwImI>C3CQch;LdZ^yj87b#wem@r V%pokPn-VECZ9R2cLsm9=*)IqemVN*L literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2af983f2fb1768ba2707b2f445d5b1daac5a2b7a GIT binary patch literal 126 zcmZ4UmVvdnh`}YlC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0)iOioTME)L1hPR&yRlOdG_sSIGil*7cp=)=HTmY7qTTEZaYla*MOsGpOVm#!aN S0y`tEMx-p*#`t*(V~ zh1P3%;)>#&9`4rHX2?j-C!osGH%qh zXyK~T%gkVyYDsHMiIkczS*SF!55C*`VTi`esb!2WPVckJH}%K^FMvBHR0$e_2f-Jy zB6vzN;x(jd0R7}{&#fg$FcVlk{)Zm#=suT57Y%6Ibtx7jv}L!S?woHQwC63|HZ<}7H(l1~B(%>y zUp@1n6hJ8?82)XJ-D^d(p)Pq=n5I=encmvn`|-WflgG0m;o;kNE+dr4{xkPCG8<$1 d)KkOu`I`U$ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8d98b95901250dcbff7f083ec8b3b7f892c1f407 GIT binary patch literal 16972 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 CmvlJ* literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3cadcc338998cf3caf13fbc3281c89e309fd6357 GIT binary patch literal 16821 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2Error.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.OAuth2Error.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3b3bc1a11b8383ca2dcd8b2d9f1686ef7116f94f GIT binary patch literal 159 zcmZ4UmVvdnh`}VkC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0)iEh@?{VgLiC93}>49|rD})Z*l#%z~24{JatdA)l`6;P|40Q~QJ`Bu2}TCP;w;(-@R5umj^V;-7CD)E}3kilHjt+AlWA^H^k zA`~6CWP)2qp76~E*NCv>5Ttz!(oP}m7}7S7b_!|dKqmR792h!=qeB^Jj<9@MKykvU zW=MLOod2&^LOzqL-^k^8!idTIN6eH0xzY&domXs&*$ouFy~skkZ$Cp+Vy%H(Z^9cW zIWXL&zyrkse7X~o1T&pW&{oe@3W6JHOP(-aC40cdn3_+Ow^xW#P^II8ZO7@H;n?Fq zuj>mQ;DVR@A5h#Aio2K{IjeXqbxeMxbMhw}B}+>D&S+PLWW+XMS2)sENh3oZ@r!DG z)hKTn<*obD_lYZ2M~|-tb?J$9!Pb0E75Vw`(;qzSnJq%WfkHhhNfbVkg*zhH;NC-~ zYZP#6Z|V7w8i{JDls{z%`6pHdSu!UHN;TgwQb&H_0Z=ue(JU_t0IVpgPjKP z>C`Y4B)gYQ_(W_ox=uO%Mc0^!>ROK0iPUx#nsDVjq*nH96nWe}suiU~xSkiA%Mzil zMFrtbUR+0*REx(Q*COqRylMU9NSmEhoo*v2p?1&*)IhtV?+)I+-(4klk&$m?M*dgt zWX~_p!tVZyUt@6#xd_8YhF*3op1@=Indj;u?huWkLpA!PYyX;|5n|HQbcxe>(WTO5 uvUNKU>6DDM5?4wpgxj4DulVIQXX0oG<;=ylxpcf~CQXq-gMP&<<9`7Te8Uz1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..029e2eb8cea1165d244555675bb26a8387cd2f38 GIT binary patch literal 1469 zcma)6J#P~+77YRAf)K$yyNRiDzS?ivlmX=* zAh9wcBnC!)KoMi7uKWiEhKd0R@%k>8YpMe!gLCKi!;hc$dG7NMQnrTp+B7{I85uS= z3~P%WZ8kkCf{u}}>uJ`3)^#t?MtCCRk(MEND+_MZE!xP}45SX9h^>yWK;mCf70HB8 z&N0rV3o`YHxz->IrkwU)v28{>AQgSUqB);TFaRUhJ0R>9c|!_5sk&na&F>i&!qeSI z09kNw=`px8g-a8-)WM}g_y#TTxapzhedKF+U2-;ordZgds|YD1X>TlM8Zi4>Q}gwl*Ju>iDL zCgadT!dhDKZZv;8(bCQs{!h8*E{WAqiP!Odyb#BW7%m_IMl_`b6DzVI`LUgAl4B1; z=0{e1zJweYLY&BvpYk?Sos?o!(2!Uff#xXM4=sSm-l9}=Svyh!?bN19H)WUzmZn8w zJ{3#@Q0{eCUQ1+#*QqB@c#T>-*Lu9xQrR`ovGu%@2Hi7za6yl9g)MWcwEu tNpJtfui3;x0g&pEk6xBG7u#w!zw_O81iJ|1{GploQrf@lU_{XO^j{Y_0mJ|R literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized new file mode 100644 index 0000000000000000000000000000000000000000..00a961b37a56c0491788ba5db40e9db805c51052 GIT binary patch literal 462 zcma)&&rSj{5Qj(pBoJ@D2W?`EiFzUg4A})m(crP!9hd6vwoV5{4?dBv<~!If3m8xK z(4>=ezTfxz`i8b6m>9~0v!u)HkyL?ihMtAPWJQ|ag;6VB9*e{f3M^A=bjjkXABN#F zq(2mEQ{JGnrgR9^Y2*!P#n4JjiVR2blX_J$S7jz|Ie;!=Xd{s!hSS*d^5upv z17B{i!|=~9I3!FpVZwK$U*HoC{7%P;v3jhn=Z5UNguM{P`=0#U_ZM%k)%0Y)Cn0Tv zcTMhAHUm$n2Tfn!E=Xt8zl?^HXw1+Z4dTW9Y%!TJbgswK>HHy@Gn_4%tviP_$;5DNC>!Got3{{pYxdhzDLLr;SECROUuKwgGqzTfYApUL)jn6U;fX)_LOVPrnu zFf0>OZ6=`=NogcL3pFb-y$~kah)_$OghMI=en(G4{tZQPJMC`!;Kk5P6qA`nI2v!V zrz|Q_s^}&wdX<68{~ggESu`xcVc*5pDNtX&@*#+!BdS6gVf%=1{2&NrCZa)Zk>%Kn zp)IW~1@Ge%c;OVY=vuwUR4EXS9Y_?*$I&{vk$Y7^4CYqn?g?aPn<)`kMwGVRu zRWY6ST?6Uq=WiQ(`&TOKe4BsYE}cKs*n72GA?5PrI*RPh)pm|Rcta~C5|lc(XYb~j z=5j-_krG7a$GfdxxZk>7($+yJe0>Wp9sFjY)XQQJGUM#sGXlAcmPLOk_c;u zh6_W87Y{XmcF(lF?tVV;_)7r(D$FX)_$qUZXyJP zknpC6gj%D#451m2%$xFli0XGRv%ZJmUO_5L<_-}+^v=>_zjP}+qM7z literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized new file mode 100644 index 0000000000000000000000000000000000000000..be89d912a67f9ce6228c166d0c1cdfa18daf42b6 GIT binary patch literal 328 zcmYL_ze)o^5XR?D&iJR$H2MPCZa}QGFen5Ar>WA2h2!2_Zq4rPIlD2J#Tgv2o%Ssn>ju_{M7qoJwgv2Y|Oto%$^ocQ8ENXsOw z%A^>CGIYfKGPlq~tYe5$Sd|);aUQnPJAA;-#4Fvo!0NcJ!j}C-Pb_-k%xX>2D_gp~ zVQFlpa)q~=g7@p``PYB9PMd*|xraxH8hm$&r>Y!Nc8;zHz~TJzdRxzb0&oSJC?z>J z;EcFtXfK(6chdTJecQQtUxBy>8`@&lL+LH|Vci!@uCO|*tCMbXRy17;8i$NLBxF!& R5A8;~RHLahg}0a*{s0qwYyAKK literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized new file mode 100644 index 0000000000000000000000000000000000000000..62cc96f4be13e82d1896b91afb4ec428b2d48c6d GIT binary patch literal 2051 zcmbVNL2MgE6#cQ?I7u5CD6|csr9>bh)a(kVkVq;OCuynGrABqbp#sWecbuJOyt~Z) zB@PFa16)Bu3KuS1kT_IA;sWZ0B95GTYDEi2ZX7ruBuXp(pRK)d8Y&A*{<}MW=FR_a z-v4v?ci5F0n2*hhlO{$*D=j11axFHiPAdJ(C|q}9kzx3Pt((vTJ$yL$G`34Qf8 zEx178`o2ulh6$u0rXDWV+?&0t`tuJz?tkZ68A_*MOvfTPC47uc9Y!%UG7V!LbdnRV zSc>+njnH#~{#Ar>nk^$#$zGz+>04yMU|A7U8;3r<_Q~fPOCu3?ye=$*vPtL=} zPjCNqI48tM*uUkFifK8=JCa2E-_X}DZ2s~bf$;v@Xd(ZV#g8^W`|jIgW%4I$dpPTR z91J0h`dU!|%&4HlX}_N!4Cg}#6+VBO(#o_xlE0T#N>VxyA||u0t7Bj2Fiz2>;Y=Dr zkoG*sEeWXF(rHSw`PPS5rlwDSLt9e-;}j=AI63?5aB}Ah-c<=qSqo40d`AyjUkB{? zgtd?Mg$NIvc&R z>}|)n1KeMqwiY}X?Uv*^4-9+o7z3T%T8I2$oy0UhN30#YU)Jm#XY&x7y=?ZeIml*` z&EssQ*gV1J5Sznnj<9)(&2$Gy0gd|N!o{WL$#Xn3PSn3VFcFseE$#9*l>WJJ>avwQ zNlmD>O`t;b9v>LBww$7&;?5biO}vlUQPQEJlBezk`|_G%HM;dEMG$1xZOT;wN>|n-Dcp&A&yd*|xt5Ymq}O0?ajGgL&|EYwy{fT%D$BCtAL0h+P@%Aa@F?Vq)DT7h$Zq d(0KjiMI%LENqq@ncRsX6btyZ&upEAS@n6F2h>rjO literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..a9da1af34f03426915cbf3c7e00402a3009f1928 GIT binary patch literal 1313 zcmbVLzi-n(6n;sXx+yL6XZj-p5`vA|qGF+~1Zhjvh|owa1qp%RVqcSM9oyWU8#BPf z+zp9;0I3q47#LV6;xAx@je(7UfeD0o@6yl~7$PG1vmL+pz5BlVZtn|Zm4wAm)@&6? z5!5y$Yw%_$w`|4TSPK2n4q2@0)3zH*Zim8i?O1VXSMX^aABy-fq`EhSAKrzXkJr+W zE`ue!8{rlYG|ZNf-1&ptX_GrGa)-zrB6o5(PY82qWPGi0`o!^^eCjEnh1VM}s(SsSw4za}rbMeAqs6Sx^>c zB&4!1BQdapn2H#gI)RY*6Brl}0}|rdX}GE_sGM~6-FtqYzxVm`tFKT}66S^MxGIq> z?zAQ8(Y}zIuA*TonI5=;q`EufhC)&|RaCl*v`td3TMZKrFaq{*xC2EGDnx6^Hd0NM zhU4CS@{rV1&3OF=N#;DL8Z?2xY=7RT8uPUn2{gtK*XcmR$q@)Aai{JhcHEiE5~O|6 zV7ms}T@akpP%{y$3qjly5ocg!_NuAJ?|NTtX1D|2|PL|90{5*0VRSXN#Cm`p2-} z+O7gc?6L8GcFTQc3}>t}uwueN!`Z|2U~25KfeD}|PZ@nz_ZrLm*d$uP%q2UP51x}r zR?JY%Ktr|F2yU;;tOx$mEt|o1n*VIaUYkFBT%Yw4POnN5YZ@KW4|;S$3O?qhq2e#J WZZ54$N+L_~43Zdy`ltlWEQ{ZvS~~*( literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7e4a1ea71126c00e7a2015c60d6e8091f37bc3bf GIT binary patch literal 417 zcmYL_y-ve05XUbm75y0akboC}HI*th1_*_!NTG$c89+$jCT?Qt#=*YOvhX%Y3_L^; zPr%AMFfcG7A?yIECChjA|M$N;KfOayNpOXX9Fpt9nACug`J=oJ!x4UH=9pmUU1m`qBCK9#jCu0$^AtM7$b)}Do z$8Y>x+_%B*rQbX3B9t3l|KPOmo}K&vC&-Cv literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5c30d3947e56fd1d61a2813bebccd833cfbb059d GIT binary patch literal 16587 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 DHe}?M literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.Jwt.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.Jwt.serialized new file mode 100644 index 0000000000000000000000000000000000000000..06f8ee1babad6d1d3feecb7b8b1dff1079308921 GIT binary patch literal 831 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f9b8f14f8f7b8d2e286f8a1fa0264dd69865ae20 GIT binary patch literal 16594 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..212b70426110328919365ef0b88bb90eab8f122b GIT binary patch literal 11427 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3ce7ca5624e7afec027fe87fe783555adf58e831 GIT binary patch literal 473 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..1e0c8c6a082eb5e8415cbe249a7832adc63382a7 GIT binary patch literal 684 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.provisioning.MutableUser.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.provisioning.MutableUser.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d93e5f83da7494890d3d994663f715c077a99904 GIT binary patch literal 190 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized new file mode 100644 index 0000000000000000000000000000000000000000..48f76f0f6bed0cba42222c21c6491332840725ba GIT binary patch literal 357 zcmaKoFHgik5XC1=F(mv6AweA&^fp0Y4nqKONl8df9d2podJEg_GCNy(2m}clhr}X4 zBKR150D?vF0dVXd0u=VWm*0CcPoFU72(Y0_I7`Y@W0EyqG;}5$7M>JOg_E`35|)}) zl}JISRuw3u=Ls5Cg=Ezjv5#ZvH4kHW_t(PmC}0a^rM|m<{3?6B+XT`a<|Q+!6VK=v zmhw~C%FMIU*`c)k98wczFs%F-TAC^whP~-Nl+a+7lsT>iCu&) z|AFQq-|uWVbv-tT*d+EEt+9yX-R41Uc^axm+p9OnZy&D-KxY|JAFgFsaH_T%<0I@O UQa1jf#IDPiwdb9O`}Y~<8#~8?00000 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized new file mode 100644 index 0000000000000000000000000000000000000000..929b7d477bdfc7f67662f3f3326f5b6dd0b920cc GIT binary patch literal 1187 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 ZcNnI>Cg6@aO42h_81t)aN=FAY_CG|5oqYfR literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cdc6b6b25920853d28136f0fb16cfe8b61a78e81 GIT binary patch literal 6302 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 KaRJFbGXERwNZkYg literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5c4c093b58a95e651e766439789de49afac55aa6 GIT binary patch literal 417 zcmb_YJ5Iwu5FKrlCWwX#{>=jBub`ydcS$^UoZ{~=(yCuv#HBR#)_UD?{uJ|VI!RmSlK)6*|lav9C2<e`l; literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b706114187c4d428a2e32015b0022e4bf436cc91 GIT binary patch literal 473 zcmb`Du};H442DfmkpQtUAs*r?u`*>u%779vFq+g{4VUEVa{^)DiI8{|Hg{2 zl}l7^YE#6ioE9upYP!?QY1LBD+pm}RPyb;ONHRDGY*S|yPO}H>aPF|S^FkxSWd?^s zw?=J+R`3dY&;Ns%-USsbbwvFW5yqFe1ZEkW?K+%X+z5|M86>=zen&zM`$AFIycwJi zm45JYjiP-{mgD7^)77u$IL12dT$}U?`!VsjSYd0Y!b#xDJBkv&9Okygy2)}A+Yhyg Br`7-f literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..19cfd3c8f9bd0950aac2b086810fee48bf3422ef GIT binary patch literal 736 zcmbV~zi-qq6vtn4JzcqqUmc3X467{=8v{^8MWr0AE`dkts4!Q-Kx9RFKpaQ##i*u_PqN?f)1LYIOAJ&Z}=cMO&rEr1%Fj&wdTYup=F*XEEqUuTLgz$|Yu&l`V~Au%uoAx! z6Ty|Ja-L8C^E*pQcb7eYBZy)c8WCs-ts}VFDQc36kA(5*H!Z5ES8fSQ)A5|~M%EtC zm?I0@|5LhoimqaRQ^4$50cb2-2`DU}uqRbr&Tkrm#jVX`n>y-qK;P5btt#NK$66^& zLzmpG=T)gQxhKW0LXY|5?YrOfbFdb{LJSLK;OaHT%WquBV_EHE_EfmS3+|mh+qtGr ze|f=6SQcsO%fD&;T=` y%hWqu^4~@OMg+^rqftDYARmQsIFE*7RAQQtAS4+2F3o}l2rfHW8igU>6y^_|8vX77 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55aff67094f6c4b9a588a6ef4a357f01ebe114d2 GIT binary patch literal 2621 zcmdT`Yj6`)6u!Gj-zk(92!bt@1d&R1Hz}zC&d`z;sf4zZqz_vJ*W@x-Q&gbJ@DLx2fHI0$U{riig%L-vz8!p2LDT^s9g2#8_okGlOr3GYU+#~c-Fv=! z&OP7x&e`308pNpzkR-*+sInsXy|oJOgF#7YU{vT1C;|#ID(@35jI2nFf(I&iU1=2D zkWrvlP?5qTLGm*WD2DOwGG0MpM~uN(pkh4gHx)v}3!)k}cxHc@bIM7B0m2pejp#6`ytx^l}b_&Qky29EdaRm3V^?S2-Ei2o<4L=yQBk8Hg7u zBvV*IdQuLCl!LJg{s!oo!>e^ph&~lRsa|_LCyNFkq<|3vsLS^Kh4-ypx3^=e2HWMJ z4giogGauja6+%GA%cj11ngkDyVi?#zP;}MkjMfTCep0-gpC_l?vTeh98c=qS07dA- z9tMk{^saiWml+`$0dpNf@^qFB27^p6mmzhvaGaUtrm`WQ=)qz!`6LAz6qPrrb-cxz zw?qN1|J*M_l)o=&0MesO4U1+51?=p4R>D|6t1w02MQP-)8AN=7?X^L zT_ca+To}d)Ugfv!iVaHyr(=rNqCYG{!ZNmjkj9v22b3S2RKM}?^S9_|K-U1RhetfZ zPqXYmi|}a(VRT3iC}eGCkN)@gMAz4(Ib;B|dM={P;3D+-EgG7l=_Jr*-C_CZz!@)> z8lRMN|D5~JrBYN%9N=0vn^U-?cul!BK7%fI_P-?RXj`dyB$rMs3Az*;uObm1kN*<>t0rQbn{jxKhYv$-q+)#&u9K=h>I4RW2#xNCV?RvAHx zBKi-MM2#L%TgUr_hJ0CQln^gs1ec{xHCs80CD&q^YUOgP^{E!}im&MF{~&`1H6fOE zDh_BO)NsH>sAM`qQDCpKkJc=9Oc`o+sXNKij(-^IpP)_kAy>iP1T8Y!*0$2k9mu(jjviCIZ0S>nFe zKYyya>m^U;^y$_Md%NMf!s(ex>%qIN>5{(7yH(qnW0-Sa-fa2L>f5WTDs3O~g7%ST z^2gsuz0Vn!-f?YZ*~XTPmlu5F-F`aq#F*T?QI_sTef`?m480qV&zu7u0PYRMd?9jzVNb?9P5U2{UaY019M zS+9GiZKYR^w`RjsP;Wah!&tF2!<=rH(nL0BdHn1>as;wl=iln|+U- zIk0ExhKmyxP+zRtIL34RJdJO0Z*SSVwIjROzgph9RJ(WL{8#q(q;Fb%(}{|fVTIq7 zKj%4axwoP8?D$=^O&|T)mUraNi%;VPD|XqMST!`$*|z=S^Vf`L_oO1Te?#iP_6HL1s-(UFQ${*iO&04tCJ9ba^h4x7455=vO9iH;;rkj`36I#2L z>uZ|tI=ZK0eP+;IG10dA^t$$p*58s2KHaq0(9J|%+B{{P`Kw(|CGHq@e3g0%|H{Nw vG58N?sBw!wN6!B+ZjD2XU@|phKR9G&4aXnjiXunx>|$GitGKizB!~V6OyQY& literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized new file mode 100644 index 0000000000000000000000000000000000000000..975206a90cb913f50fc09646fe3e96077c778d3a GIT binary patch literal 5860 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..707931001992083b35f84271930084b00e043bd2 GIT binary patch literal 162 zcmY+7F%E)25Jg8Kg@ug=Sq@-Dq6Q*`i6+_(Fybog;>;l0cp|Un9Yi~S`Cjt=>kXkW zB%UiHEn8O|85`<7UyM-EvDJs^DL2^ZiJaO3)p}?4l*fN$L5j8(_${ad2r`&5HC`z$ sOC}M8S$4)7Mm4%B+Uoagp20*0Hzd>Y3Qri_TZJ%PC##*pczK97AAxZ;O8@`> literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cf2c149e825fef4417e62ed8e77be5c567df786d GIT binary patch literal 1231 zcmb7@zi!k(5XQ%M7mh&wfKx!HaX6%3+hz{Yx@{VU`f8Wfv@AhH98d%e2!?%f%YGd7q zE^ceH>~Qt;(dUU*AH>M8S z)qFe!2AOWyU{^bAMv+0AO>T&6X6c(|x)AZC2Wir)SX| z_``40cR^8Kg>eyvx~JR?t>)51Qq@%$D`J5Tw>WgBbVJIibyV!6znnT+vQP{80v%6; zwRD4XVYFr}MYsAus7DX!nJOGo`0221sovhivrkW7@3kuc*_7(EbG+EOVh}0o>&vC* zFZLg=RVj+HQvaxI?o!q;oH`hJptMdN{*vmT#wvdTeki7+ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f8e27087821439f2507f952fd0ca5c8f1faf0c0d GIT binary patch literal 16834 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..76b18216fdfa72d33328bb729ea933ab50e1c42d GIT binary patch literal 385 zcmb7=K~4iP3`N~(5vmXpf;Csj9H6T~g|=#tkPuUKnKot!Of!SyVNw=I9D@Zn=snnT z5AHxhkzj}L!VBBq|Jj=l*l`3@Q6XGS#unG4R@hc_Cmb#tGQ1WoE`)0M1}&SVVpCaB z6UK_TAk2O`s7ItMqmH#IXbrjP(s_v4p0_1cBb1bWUqqOarWZ7*j32`GSr>;M1& literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..bcb7d655522cfd5b8bdd4b34e41faea36d859b83 GIT binary patch literal 11333 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 S<`<4W|LmXO+<0hW`WdQyE$S literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cb6234b9d27a9463e637ae5a999c7081de129a14 GIT binary patch literal 16826 zcmeHNeT-ejb)UC3>yLor7#rKz;2555zH-;bHpbWiUe;@Dvi3T=iy@E_-FqlNVa5aN=7Z|jhoL?vX+4vnXk(Zfc>vLGB{TM zi(d^0F&~M;i;}8`k@R}t*}n2qd;j%AGm`_NGAcG@85);QbY-lRxO0^759O9Jlq_Wk z_=mFij}TMW&-v$luj#jEyzwrrvL!9|&wqCCfwc#|^lzH`Yg0fA@r(C%+#CqR zG#bR}$b5%vK`$`~y^~`WxcSAnA$R@v53$52#OK9IG*>IJa+)~pMhOR6f)kdtgoA zY?u+vcPc^*98_Y3-{~mvz@nBs!Mka~?4e<@JA-OMMuFc9o`hjclFgDLhWZEgAT}jF z()3$X4ZlieKzp*fZ|~im4zG4Su_z9J-3?0I4Gx1g0k!L-(4ehk)b^X+jBLxuS7GF} zg1GKIko-I*X@8(!iOt1MLwdEDEnSKa8jAP!pg8Nd8%+|W_fRaO39`m!ARCs%nJBE2 zb%O5Aivt)QHqgefv&UuJZ7P?Wy9_r+{~&HoXkL}rS;~tUHk_;>PKpeC$uO|H2LqP( z<9?kiSc#3f9>xwNH@NG1l+mKO8BLY!U`Fdso(>!Gtl#XqS{e8z!z@siK`RXGvQq5GXGK$v>r)c$+4+9SWH z9DovAG_LV5R2tt&W9;s<8c!o5>!FsBC<-I1{*SmnjU=wChwVndUafhY&c3lW1Gz-_ zDB1u@iAdJxd2_)p8lG%^caccbdxlfoFB4rijUP=U2oXkN>xxw@Mmn~kvbkS`?|O*@e}9psgNF_aE0LJ7W|PELmy&R6PD;<}Wa z>9Y$v<&Y6a4VnEZnYnH!AaCJGJ{deYPmYWuKh5MxQmYOHDUiu`nN_Xo;8>Rpmr`;t zj`u++rNMg{(PS76&-y{TO6O3}U`t7Xl-QB}$j`9ro^-kSSW%J5x;s9_!Le71X1WNX zhC>Pq4OO_QZRG=I<=fcPf?+uLNlE*c&bfkmMaR&8v@dCpIyj?YIZ_>GOlkK66RhVfw-els5aQbW*n0;K`>&ohJ!|VN*$}8|ZuEd88#ei3k zrKOK|B_{f!l~|%(XJRF`LpD;&0QrZ}WGvwYv%1B0fRb&5g5D%u55le*nKvD@1M*!) zs%wHo8LlM%lxd-vMl(afmW6}8K(9qxspn?l=VLBfZA|F?BQ&h9&$<9wgBbHIz?2J+ zdesI1ic-2C-4s`T{F3xij$7|VjPXJqR$^Tpd%f0X<)uCZ0q!nlBn8G-&0PwMfSqu< z)(ikIZZUv=ViHPl45<(Kl(?bSkTH?1nQf2)S2N!I zq+zC(3f_7g!%gA_W&;ZCqxvk})SI5YR}P0wxN00-n~R->msR?dx853(eupWexqxP# zZjE}!rmVVhe=Y}(pPzF9*q5^0HNFDC_ZWi`N0zx%1i;{F(vQzkT+=E9B3|FHiA>|}R4d5bMBX)Qo?RxJuK87u$!VW%sK*xCek-WEyaM|( z1=;+PiK1awQ3UvN22g@;+x?tPNeBYk?&-9HcZ`WovV$y>0&5%uvtGZ8vF{a3|9BYD zZT@^fX_?fgBkX^T0`CnRcynkxrc;9ypInoC8ZE2|rq58Wih?ds$i?1bSq$t;OcD&d zK@8lUG7u{=qLxSej`;Q2u})mIpVhHxil-<nGOqip7L3AZ<;`EpOW%^vxF1zSIkMeHGWnG^zRvVS0|WDKnEs? z&zlN-7R(Y;c?11z2@*0!^uA$%$_$Nm8OHw_&EKHup+yX7LF4NuX!5FdwSn=UmH?3g z(0dULpCP4!TDCNS?(GtCBuDiA9L=T4sjqEx`G7v?YC+H+L2DT=pM-m~UlaG9_*P8d z1Kyc{`I&I<_8i6nfDZf7od%50x+Inzl>^t8T?{(-M)z0Hd=<^tT!3$)hgXsE@O2kp zNgncXG7$c;i(%2Yn7rau@6z$3D{vepSuT& z-@>IU{9sBMg7^vNkDltE@q@7JOvHVl#rh0FE&0DF({^WHTM<9S_IQ*9+j+T?o{y zlZTz)TbHdXVbVRhN%)!JQacwV_Le9wD?fA59yLOxdP}aSTuu*J4z8uI%Ekf*Lkv)! zw#jpll(14JHm8NFq_dolJ%-G|B^PQXN_VRSrxIJsx|vi_Z}w^o6>K$xPcKQB>w+C$ z&DNU1Oq(ksv$B59VZ-u(T;rX~g11tcbq|l-%p5h9>(Ok(&y0O&?O<#(nk^XsTAg^B zeCiWe+DzorD+JH)1ZfddQNA$t6zwxwgs$e<-TB}{RNFgaN_$9;@N(>Hg{sM_l9RQA zGEVYPN>rDaZ&b61>tu19MU#jC3#cQOuHcxhP|bfWk`QrR-MiNoXaMv$t&$5SmwAdIJAIo~`o0loW(9v1?ZrZ>^0WPuftm7fyZdyFKOP`NFkI6wvH{~?Oy73kAc3p{U% zCQ12OSB-DzHDrXpO2hj~?ayjBKuJAlM6nqz3nfT-$>p%Z90hAaR< zpjBEPmz0e_1M`BxYXmWEx%#YA;yq@%D4kDNQ>6CEUnHGoX{(cYi3~wx3$F?OuyP2E zO;2NRCvkAd*(gO0hC^a%Uhf0__$nbv<=5VWR-YMipCNL5T_BuZX1Y`{wd+JN&5cY0NxdKXLRHri+DkYo1$Kuq%+#-+_3 zuPDj2!|)&G&+2~4m83t7o>oNNwyUCNa#~pAxGGS9N=Im4ne05}WKK~Aj@}ctb)*i}uaSz`=x$K#U|f zM%v^ua=-$>3k&wbTU`LlsbCkr9Z)y806IuV_YO24MYGcd;5#ed&-untEnvvMj|0GN z2ZMPKhwfX@@U_{x7^vN$dwG3-+K( zLY832l#4G~0R0#YKQjQYmjE1fNEBX*0sh_uK%brHx*yvhJycPuxIF%lbYY%Zfxsux zjG}R$Et%I*=pI9Z-IxI|@0!p(j%ET)=GjMTQD-ssZ~-8FmGEhdv4OqcuP$ByWwwWD zeDQTC6CrbzFb6P~C<|6yFTwDBuR^~a0V8ZPi-|e~h}>1|va3h|GH*IA*P{>6xqxOK z&4SAVM{g|Zr!ZE08}JUg86d^*1sB6}B>>jXrQQQjDTWNdl~k$VSMKZtSk&Kww7!id zlXiO7ikf#wF>&?Fr2urH9Z=sz!;;VFf*mCDkODlPs2j)OYiz5WcjbNj1K{BRA$?F< zC~5=dMHkB(jO8Wtzl`RUJQk4Zt0vhOroMpsA=g(ig(|^V4*R74SEVAV-GXtB8U7Am zua&5U>aghjAXo7EvVtpe>T?J8v+w#k3qI&-fwPUUH*@FrZ=I_`gz6m_L}DRd-9Q(_!_|h$KKjbs6cFRT?E)?Q@hUeI1cIBk2m`llY ygVHH9r>RM;6*Qk@nrASWO$1}Gk1R1JV$W2NfJ&ExL&+vg9e_tVOz+Y8&i?^V@k>Jh literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..67ca836889b6f6cd5df0d36f5fd4da2370d64465 GIT binary patch literal 11233 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 j$uX8(sUS(j<MHMz7Xv!qh5JT*x#v9u&3HLoNy zIk6-&KMyEZTnwUvA+%d&1z0?wD8D2%8KlCs45<1}kH%Ghwku9d3`{-@Jb9_*Q01N} zB@9A7S&3zd`ZH5JXAe*g$YVvbZ;A#pP>KGU+iWq$HIu6ZYsUUmx9FvMmiV~Ac z98p{icGF3P<$o_V*#2Z7=~2Xk;G1pZrlqtvr)A!o@B7~Oz5TESN1cUR+P0W8RwbN`Ok{wBvdHwC>kX^O zPzP>Q?AiI|!g!}K@J&UsiJd&vNGF9!TJqv7iVI%F(TQzSBv#dob;cv37dr3qXqXmZ zPSF)m7+7-XNMK{GIH2y(H@cGPVQF9;Lt>lTt;r(#Pegx3v<*ypI{z~%AHBe0f2jKp Dg)>OG literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e2e04c184257388a1e75712822dfcbb24fbee93d GIT binary patch literal 16807 zcmeHNeQaFC5#Mt{zJL%yLcR%sO9BZz$0QI!(!k+3#Nd2jn}m-x==tv1e$L&!TR4POev{D;U!5>s@)dm$&sYRkvRjDniR3TMuRjL0~qV4=<_wC#F zarT)+NEPuP>vy}eGqW?ZJF_$Uy}yg|0$=oc{)iPce78O_?AtYG-1CoFfm3e!Za8U; zJ42S;3`d=M=$7r!_3GC6__%eztCyXgiH7Stm7a;R)4<5DpL@UYt3$;j9YRd_V#kzt z%bxF8r37M)XZ7qmxBU71k--j8=o3qm)cc(Wnobag;<`S<-G?q9rr&TR{}J@OaH{UtG=hWO3LYj>~Qx%w9wh`~|c8@Gq5 z&Trqje&deux89p2X7`En%62nwLb0?DxH>_!Q$z0T6BkyT&~~f)oglDB2yU?fHxNP} zJMR+8}#imL0ooU0wfyfsX8^%520KVG#d?{5E@zuLa|6rYld#Mv(F8}of8dG zyj-H|S-l7K602VcD$e?UzK$h6AigAKqq!gyvxkY(rXO)2B{-m2i#X`myJ^?1kFVH) z=?x*o%S2{XEXm9Sd;aO?Hr()sM?1v4Tg9AV&#&2GuUJrZ>&}5@ZOHNa#6{(*9Rz)z zU2*&aWS(GXZl73KacBTS>c+V0oj2@O9Rq4X%?U@nN}|WBG!rlv*0|@e;|FBJjA)`! z5Tav8C}!D>MksEZ(vk;w>kOz3(@l1#Pz^Y~YggR|VHksCv!sa5_JJ*kEfg15?b=Yq zE|MA01}t`UZD}-kwTp;Fu?_4l4#kb&(5(|ty-W&q>!IVROiLD{-3 z`nkuU{ek{aEX#H(((}}8$E0|>qPV*S#ZkLnsgfwIy8_1_AZx6;PDPVAK#zw}_2Y zk6Pq~5tTFr@wVpZDtuiXiVGsxL*AHYGXF{zwCp=}=o}mxbIJ+*y_EvRPs_wLmI4UH za*3MvdD9xJ*ep>N#Sqq*@4Y#+}sFGmSmo|;t@U?_o z2W>|_jhybL?~}JshZLWlP7qBN|D``V@~$1L9E*<;-x;ow=A!e%sqE)twN#dyc^gfb zJLRy0%+etgZ5B zBxq^i35Mc)`4OXooO;mg)yM0sxhzIHwxP1IX59^~M%51Cr>wG9t9kXn zf>X8nrGUsK5QSPq{ImNP+)jKe(1WG|^z#(fmXq`TCr<~DGwI~9{sbTIa} zK`Exedl~VV=Xa0VZoNq7kXvC(iGf0~HvW;Gq1QcVa&v7~kWqJM8&(jawkOj;l5VQnCQz>1GKelb$? zaq3ZUBrCg0=f)Mfhc;Gbrs8<1iYL6`!=9`5aWN57996vDa;Cfj&(Tm^q$s+)f+Q_@ zyoX|-En1N!>UBm|qC1>QY#AVb1Wm#cUQ(-@Y6pZ)9igB#NY?|e8TL%54%z|fE+y6Z zZlny;>b}La&+60KKxzi>a4ujhakXR&y2*t_$rx8VG*zsj@Oz1 z;KfY^@H-|E3XUP=As?L$>P)OSLD_e4C|OXOR2jbZ=z&nIX*HxwWJO{d#K6Ubckflq zlw!eakE6JW+`yG(z5vy(3NTxw^sOBbaA|EL>56_TI)BK8ioMD@8sCy>scFirDyaM}) zjBMU#qG;GvWC6a-0HNU9b~|TN6oP=Zc{;7-9i!rtr;_Cm(=_j*3v z=8wCSmWh2j!v0efcrWI_n?vJ+oEo$#KDjXZR9cwt4j-ai6$M?Okcz#l5KZ^&4DW0MbMfU`eh1hhrX=E4!`qPAdLk2zJap+oA zb`H4>2l=bw)?$|o%#;0E+^?orEqO;T-=I(8>yrbWX7BnMki6as)0}%~Emy^BDfzxV zi3DL$e+^IqhvH0`D_W?#m6#R{OR4rdHS*vTc7l?rNm^6Kzlq4kn26FxR$%*RuQR)$ zn5*#SpernCQ~ukFU5pJ)t{B^q5NR9prxs&dK(jtfiop{7%VA`X6uhRploIEay~ZSk&|V($fARW%f}x+%Mj7|*1_f%}t!Id5 ziJkQscH$itZ$BVCNr#1Vobp+8ZyG>upOW%+HHQ=NedZ+I8t>!*{WZbvya;m+XvZM& zc}0fLj9FqTZ=fILAR%K!@0%JZ&(LU>Vf+VZeu$=p7BM6Rjjx}fNvqn_2F8D$14Ify z?`brAhU5xr#?l13cXP;*9MSt8nlqDATifXD0e#lhf}r1r))HPm3ioKgM(#cGt(d?E zyfFdu6XD+G6vhmI4Exa?2aJ!JB&Ll~pVA~^3|}=d$lx1LUqkbCG~X}*p3K4UxCt;V z59v4=2)}7!m@+OVuXx@^bo|H)9EVBTvjP*J5}ES`^1oVh{xrUxp}T^-rIo5xll*ry zTr8u{rj#LwzoBVgsDS>*Ica9EBUfsxlGcZx&zgebk_6?AxMG@0m`|0yXm!P-v`VWX z9Y-gQpQs?%GsA0KhKj0_t;!$BC;l#rCy`0gm;S2Vtd~bA&yI%)Ru7|>7g@?Q9;7r5 zUD#BVefbol`Gh$<#i?AFk7fb*NQgye1X}^@WY%L0l>JF&I^sJXj-kgh;FpfO;i!>^ z9pGD+t}9{EO{q!vncz}7mr!iUQC?Dh>Z0AJgi7_6R8PK~?$R7wLSKa?84fxbAU|!B z<{&Cz#Y`-V3s+HRJ|7zund_%rsFo<*tsQb6Nvx|C?l3G;Fv8?&3^%s5J6DfvPBnY0CbdA$pw?Myh=rN zb`VlIUp+Dby_<<17XqfIH_)VHffkXLUno|$7>O*QuqmS0K?Ugl5XJlo^Z}{`9#=(^ zsQfIe#%o#)DdEqRancqTP3l@D_OsYwUIiX6 zNXz4rvJ$APUNBe{H=r$79yLn5dsG*t^XY1e)IRx(s8cO%UNkR~A&4yJHNhViwxiMM zX$-C-4z?Q`CCfp#M@&t~eIOrSMMSCm+ImpyGePe2M2?S~mJ23RnV5_ylqzP^`@D*V;;O z^B@tt!!XXN2@XsKp;M!hUsb(N<)d4gY(#zI^gv2Qv#FS-FH#WAJ{HX($n8!v{gF`N zPFa!^?%t$C&<4}Dv1gKuvBt#GbXO#m!d{cs?L?ig>IFnGg~RkF6FFA`@x|IWjio#l z9TGvYr`8BLo%`Th%ih>^^2I;Wy>p^LmA$z&QXsuKZ35>)TFA@#%}a+2;W2<1NpOs` z)MR8Ex;X^^FD%##uP^~Lr-EJhYCx?q0c4Pl?zLzxN3+fZ;5#dm;2TFVgCYGs4gebr z4C+A~y01dR*JkZvpt`rw%_L%gYYYrB2cH74On|p?FeCuRasU$17&`|hu@#^!*y~La zP7a1dx%jjOkdMLeGXd~M4!|yhMCPR!;CDv=^6W&{E!YO}p^8$)+3|;@3-!zj1nxl7 zhsJ!iq+Um%`yd+Z#sq+R*M#nVGy`Z7&pu*{I*hR+8G!gz!aW#c1N*dJUAzR!Y!Acu z;_FZ%Lgp%A3ScZ!7Oc9QgW=O&g?u{#M%ZSi5_JsVo2yu_R}ljw-gKO;M<1Xwj%EVQ zq{#zEZ!GGEFqVBA@Bz9RAja@z6T@RU0NT&R-UCoEh6KR5RH@)s?(76u)K5cN&!9=9 zoj%f{<{gqvT)jUXfGo5F>UlIQ`GhXmK{5|9z>AT(aU7mvTjjhf@8j5;~X>m7+MLbJ8Sp;z01sqzQdY8%pZ*M`0Gpy)YZXPaFd} zc~O`HfVmlfchQ4`q*bl$wdnw6T&)AKh2~+FuFnBrkqOXdEe`XL2FfXwwOLEUZB*0UPYQZ$61kButW*3@N;vZeR z(cDZ;oIui#wOV0!mXH2w!fltgU+ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.CsrfException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.CsrfException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..16edb818a7ca2c515ca0363e0fd5b0f27480a41a GIT binary patch literal 11077 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b7798b44b73ac581df264c2d6228cd6be8521549 GIT binary patch literal 11241 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 RHokKB#b^Hv=gygM=6`1(@xuTB literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..171eee2bd8e7c029f5d8c49f738fd00b18ff2b26 GIT binary patch literal 11227 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 OzVOVSVBa|(&;JkJn(NX4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.firewall.RequestRejectedException.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.firewall.RequestRejectedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..47de867dfe1d93043526ec3e4d4551e4226b635a GIT binary patch literal 11020 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 V&b@Ja<2%Q{_WB=T-#HV^{10eQnGyg1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c35bb07a8605dd2be856147bc844caf497d69c96 GIT binary patch literal 1787 zcmb7E%Z}qj6s?Y(XCuu6&A@`;6Vhw}jll2sJMp8~OikkMgh|I4yV9KoX(T=a3H|^+ z0+<=wZ0J}mPsw&g6K0F|HpH*as)O!WXw;PTMOlYcOM~8!87DAVqf4S&31P%b~PTADC^H)tb|GeqOHW^|bTqoGjPvo4CG#TV!yy_U;8) zZTCE|j>U&Z2)*$$MFYD?>>$t+iu!?W=OuoqIQsnxt8Pkh=XJzxnpz zlOF`s(a~sCk-1K0w5lyMq>H+27S(FL+kEgLN9VOmsEqEyuM17Os$(i<$UEwRt;b2| zQPh>Np}A1j%p4P51KW&JiUgca;lBvrdFW&~4^>x*b})hycv7n9vaH=sHn1kSmpE<+ zp^6V#hjC%$rtanu^bk)2SHe0>o`rgV9r&C?zN#8oC`0CM?&-3ANZQH-Du$91E1Kto z1voi{WlF3MRZX=#(StNQgou175sJ$iASu{^1!c1YhfW5u16R@#)i5UzK2&4ZFm*}& zk10eazz{gH9mmQ7#WHNxykVq%q(G!@U`xkX0c+P!)EI*;$Fk>4{4Cq;4&4a68v&TS zd&8v5_rQxk?>+hAoxgq)P|rex1+Y7-<|S9_c1`Q6R)-^4N#&XenJ0y%Fknk*OU@2U zqM6mp&9%Dw7o=X2R_wdY-*8dXF(wotxbL^mW0w2zzRUMo4=?6M@HssNCAft06Y?)F z)xP#3HGkS?Vqm5?2~EkI0`FoN?XG*adfP@5Xs&82XHi#MW_GL4V{m1}L?5WBW+y|*y zn4QaEYQ~Y07VO*#u8$9K9Z0CfUY-NnLpf3k*U$r)p_fgtC#MHLc1$b@PbDS_y+{pB z3L~atCAZTkhFVyXaz*8R77}C_PO`w5czJ{Y9zjz<{@uhfLk;e6s+ypEL6xANuIGhQ XcE;2+Dcs34096gcNvLUFFm?X{R0i=q literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SavedCookie.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SavedCookie.serialized new file mode 100644 index 0000000000000000000000000000000000000000..16a8258f007c5edf03bbffc1677c1858dbabb208 GIT binary patch literal 250 zcmXv|OHKko6nqdE2pbc3UZPnWS3&|d&KRZRuXhi4jxE#OL-(5jH=Kw=cp>lLfLg2i zq*8VGhHeaS=|e7J8H~%{0$SSouojV)RWST1wzLotYgz@`R1{gLqZoU?HUuZMi#GHn zBo=qqIcZ2vU6RnNDMaI43caPbmK-yjryp43ut1j&6(2XRQb<5ee>P$;Dn@f4a J(7Aue#y>$WN(cY| literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..58449b0e225938c89ba127cfa45d72b240900838 GIT binary patch literal 1022 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

!t&ypeegDC{?7ohYB4WoII3I3=MmUayM zXZfRX7|u$PSLvtLu;J-mcsb*RrAR=Ro`!iPPv_xG<|3TH!SDY(acGXeW7B2TxUm?R zB_7x+v7)J`=NrTyQt{+rS)(VH9q>GlpWt!SZAvEVXG#3!Jr?DA`LB-{?4|=fN zeL_O82&K>Ql}RYZJw`TVyJA#IXLMPp0^hTihER`TMwa23E0Ba_S8|LcS1L#nk^iG}7 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..bf05c7183134ae7534d9540df8e9b025d8e2087d GIT binary patch literal 354 zcmZ4UmVvdnh`}MhC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(c(DK5^;&(rfL zDJcksu$_xi6H8K4T+34PN@mu6liQU%*_(-hp`wVv4zF>^`9-O4^N`H~nh!Rt@Tss^ z-Ksa+NjA(esko#lF}Vb4DA=$Coxb0XSQl_Y4Aa5pvgG`{lGKV4J;#EAoXq6J5|}%Z zT3*L@xSxH<#K7pqz*&-+n_66wm|Fn!plDWNS)yKPNoI~7*b@JwtkmQZpI%NsiQL*1 QAgc-(7#OE53bE+{0KBe;S^xk5 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..279bb818bc01c5812a2aba86b0dfa51e324b1bcd GIT binary patch literal 421 zcmZ4UmVvdnh`}kpC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(c(DK5^;&(rfL zDJcksusu_pGZORCQ&U{aQu9hSbjc=d7P@N9#K7dkz>}9+4p&veAmo#kSeB@t15~Xa zTmrJi8mJ~eCk3vikfDx&v7(5<9K$1FQ5;%1TWx@#*FClgO=I0kW!qfq`+_ OqL?735(Y*?5C#C|2b%)` literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f2e8085330bec37cb385e2e167f6b0a967724da1 GIT binary patch literal 783 zcmZ4UmVvdnh`}enC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW8sRtkk@c%;dz9{36HV;?$y&%>2Bd)Z&8tyy8@rrk>=qc{ivN*GK**6E{Jrw_AEA7~W_gRRpCTBq++2{ghQWEQf$E{P?Hg$#8Jj6MvU z#hK}Oi6x~)sZar~QlOhW67y1WAR-k-49*mI5$3alCo(rQy(&4+1hSMbIVTes2q0&8 z1^fGfZLTN)2BtA-Hi3P2sd1aV#<2zZK$D{xSd%~=E@5DbcB&{SEdtSNK8ycg;|O`c z#K2Hdz`(%JR;^T0S&*t^r34Epz4X))B^{;YjKrLr)Vy?%RE9xWdbxXGR=#tUW0gy2 zac)&WLAI_}n5S1zPKUuePQJc~6nK7StHOo#LBb$|V+i`+n=54-Bg2Cg)VQvhV)WS@CLN$e~+#zBkZ} nRalsmJ7L~>^`ATQ&vCQ&pL)wQnbXifr{hq2x2u6-yLAr$lY1K4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized new file mode 100644 index 0000000000000000000000000000000000000000..449d5b9a9814420db1f69c3f4be1de49b487a2a1 GIT binary patch literal 130 zcmWlSy$!-J6b2tikq{+=I2{dD3c7Sm@WpZ*ga7pWoWM>rjKl!!KvJA^SKa$ZO<}qw zwyI=y(T}OSJ!DKA{-WA27XSbN literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2ff01fc9d19abc205bb2927323a61a932205a7f8 GIT binary patch literal 115 zcmZ4UmVvdnh#?}sC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDE`Qd3g%N-`630*dkrQj1D5Q;YpeOA1O$R9q`cQuB&4^Yb8ldwY#P-vrHsnHU(O L7?_H(D+(9^Dt9X> literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized new file mode 100644 index 0000000000000000000000000000000000000000..78ddecc04253cac26a4cf70c69596d048012bfc7 GIT binary patch literal 306 zcmZ4UmVvdnh`}SjC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDE`Qd3g%N-`630*dkrQj1D5Q;YpeOA1O$E>CpN|LC__mWhGUhk-30ELOr0pQyUgOUMHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9%jb4yDSlX6lWfkLTyC7H>IC7Jnot`#MzdBs3Rv2#u)P}sk;q@c8eqx#L%V ziZd}V`Y^EPLj+401bng*%M$fVOEPoxeKLzntSbtDE|CHW>VX9H9E*w)D~naY6iC6% zB{uuccCcLnniI{ym{`If91SrdCowNw-#;lUH5p_`X%Rzcv=3<>BE}!qDnIl4_s#s> zz{J2%QNX~!zzB4%2Wj>=7p10v!YeT+peVl}wWuUBwHOjgmnXXCfArfd3l1bUNFbFk zM1lOFj}|fdu!zwIMhXanBSs$>G5Wa8SAj<{9 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f0703c6b92f66fc4089155b7d0fbb7bd20b69546 GIT binary patch literal 361 zcmZ4UmVvdnh#@4uC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9%jb4yDSlX6l6N|SOjlf6?bor_XaQu9hO6LUg~Q;S@ItdhzL?tc7_EaVEA7?^z+ zxKlEV3vv=G{eY&IFbMf%C6*=X=OpH(>j#&BthM%GV9HD>VKDUpIz=DNDf%#{=mVVr z!eFQ91D&GpR9TW*4Ajh$2Q;{lp^kyEqM(F literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5854d4bed3ca1134d5df858f69820f299d9af0e9 GIT binary patch literal 2288 zcmb_eZA=?w9Dk@lHx^Mw0+|sr2!xS9uLIUqFu~H*LSKLt+7&v(o*vis==JV+?m1|g zqRwn%kp$h0xR~LlGwuWNCB6k_rtZUL%*1TQL{xl9oF8VEpo=-~Z+J|35c%8RRGk*d!D+DKg^4XavCoHzc9BN#R%(@i=7~;==TSDvpUJDD$Qc zH7xL~n@iad*T;#Nhr%zVM~+-vpYJn(Tn{LwTj@Ltv4m_GLpGKm-xxSOgo(*uVwRa0 z!a^U7i6Kmk?e;*89#F&zJb`p1F()d#B>Ff-6|jPV|IR50%ndxnuHm<<;wSb|<@q&Ha5ltoBY<((85x9|_cjMda?{y`3(uRg62g+AYnsLI<`ww(xas z=p}im)8~lR3obnMe$%EiM;T2|Ibqr!FffFgH3^Y%>Pqp|+%;W4F6Y~pHS)TDd%@Jm ziQ{Kp?%@B5p0BO<%nU5`X215t+*oiTI3N1>U}a(6h5`Tl^siOcv6hL^N!!VFM+cu@ zdaUrp52{`zhTgd_No!XWDjBW&YON=G&lnq-oNF+EY!4`an0f%|hIBE|O4k-vw)Jfg z!|Mxc6+S9LtRk%^kezudA!vbOpOBtOB4F1S*cF8&q2&(w$*25VdoJNGG;QanZxU*T ztFygLGleufI&M(u`+ibd`*xSnmRiY}WgjJb-|7w*0|nm-o9^~Lw}4ekn!|NO@EEBk8C9^QFn z=IN3NwuHC?G7dS-4#P%c@41D_@Bgmtty+jT7a!_+cX;j-tF_ctg;o!i;xBrT1SyKrgY4F_E{(0Uy9g~PlVn<_olVl2iA_8d zi#HE?5kye%EcIAH5Km$cB1ruM6i+?q$%Dlo;G3-LwgtB|kV*3L-uJ%u%{NP5p;-zT z4aBr5L&5y%DM2c9J`l5}q;4dbO3Zoc=$l09x^L>0`ii+kvA{R4P$#G3dZ~wB7P^LW zE5C0Wkg=gvVb8oKsgTF<`?kk1E1ArtGh#aNKr}&$?f6lZ4Tw(*4wM!ds5JhI|mEU6o*LaKpiC~ z1W7b{ytsP!;R<=&1eqdaCA&%E5CAgsS-oOWzM=4LAZTh8ty*G^vr5QmK@eY2PphAX z5eYAYSEm#Kr<;`9v8hdpb529^N`uUf5@q{EvK5hO?0Z_D$%o9zXqhI%0_s&aE|_+&5?qwEcDDOy=V-68gFHt$V#?cj=P>kXottT<^0pYx{mI94y@Fzpp0Nk34vH VFZg+M&vNF`tF;%eKkD(i{{Z(Hr?&tA literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..36ae5f437c29b8ca554c8e197a1bc36d1dfb1d05 GIT binary patch literal 4101 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 b{4W_ANjhg0a&}v%E1)O|qh^HZe Date: Mon, 5 May 2025 12:43:08 -0600 Subject: [PATCH 140/504] Add Missing Serialization Samples Closes gh-17038 --- ...ringSecurityCoreVersionSerializableTests.java | 13 +++++++++++++ ...uth2AuthorizedClientRefreshedEvent.serialized | Bin 0 -> 3632 bytes ...ation.event.OidcUserRefreshedEvent.serialized | Bin 0 -> 3770 bytes ...entication.DPoPAuthenticationToken.serialized | Bin 0 -> 756 bytes .../event/AuthorizationGrantedEvent.java | 1 - 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken.serialized diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index a743507e73..64ff084274 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -139,6 +139,8 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authoriza import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; +import org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent; +import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent; import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; @@ -160,6 +162,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; @@ -184,6 +187,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; @@ -364,6 +368,13 @@ class SpringSecurityCoreVersionSerializableTests { new RuntimeException())); generatorByClassName.put(ClientAuthorizationRequiredException.class, (r) -> new ClientAuthorizationRequiredException("id")); + generatorByClassName + .put(OAuth2AuthorizedClientRefreshedEvent.class, (r) -> new OAuth2AuthorizedClientRefreshedEvent( + TestOAuth2AccessTokenResponses.accessTokenResponse().build(), + new OAuth2AuthorizedClient(clientRegistration, "principal", TestOAuth2AccessTokens.noScopes()))); + generatorByClassName.put(OidcUserRefreshedEvent.class, + (r) -> new OidcUserRefreshedEvent(TestOAuth2AccessTokenResponses.accessTokenResponse().build(), + TestOidcUsers.create(), TestOidcUsers.create(), authentication)); // oauth2-jose generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException())); @@ -411,6 +422,8 @@ class SpringSecurityCoreVersionSerializableTests { (r) -> new BadOpaqueTokenException("message", new RuntimeException())); generatorByClassName.put(OAuth2IntrospectionException.class, (r) -> new OAuth2IntrospectionException("message", new RuntimeException())); + generatorByClassName.put(DPoPAuthenticationToken.class, + (r) -> applyDetails(new DPoPAuthenticationToken("token", "proof", "method", "uri"))); // config generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message")); diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9588433f2b137e0f14b3a31f403174e9d5d2a4e4 GIT binary patch literal 3632 zcmcImO=w(I6uy}>X{Py4n`o;IQX^<---|_DBn@%$W1ITgN|Pxx{)9X4-I=+`oA+Mt zyOT@|kt|w}LJ@=%#gz-83s)joTGyf!!3v@aU3Arjh;&ihNb%fz=jG1NqduX{Vj%b3 zdw#z2o$s74{zPpdLs_2{j4)u-E94n2ku{&K7$LFCjPiBE$7NnTX4ozz9yiFU_&u8u zXX3|a^gZHC%a7+so{_LfoLO<{?zck^`wy?~N}(1D^$8=jcR8B2z^&Qf){NYm%B`u~ zn(+?DD-0cp3*PoUPAc5U1c6I!%&G6mm~xl?So+|^4|gG^Qz*@8iG&=N0x&bUj90Ny z=F~Oh&9k{>Vsq3Dy_B#KDq^2Y#Lzq z4Df}c0ZYJVy4Wk2^IQ-KE_E@*hiY0A$wJU+Rp}(3k5>YKeJl~|U?C!?2IlAQdyM-N zdB8hmq4v=B11LS}RdI{5oAZQ2&}lA;u&^FLRCIXc(4>li?T9`;Z{oBQrXW-7*m;9TLfI zNq6zmm?v!eol7^LIdt;NErPJ3GPln?y&z1td4q*&FUY6yNNadoP_99L#tC6K$e)f%`t zYM&yQ5eBYKC32;twzdt8<~Gz0_gH8s(pTBLeHgFaRD z^fUoMcQ~3&?m*=bXGYLgIhk`LNrATNf1xkclP+~KPi#gcxjQV>6PCRUE~&C)`wjtaPbc=MaE&9vqrC1_wO)cb3j|oo;gEt3 zq}AzB3S8_|hM!YIsk{0`-G=}#BnmK5^EFVT*mlPp{p6noP^U%I%gDtt6b-8B=ieaf zusMM9#mDHpfhQWY-8Gw*tc|A4AnZhWS}3cH0J;}DnB)2pcp3-5xwIT0Og~L8udP56 z=!14%q~XY@ARBn>kOM}4?JI|b&3So$)^h@%dN8R%d_YR5#z(QwRZv;zbD!rAj29f`YDmz5k%OR^%6*vgY5T@&n@g|N}?6Yw? z5IbO;IsiEp^;5{E@-)?eLU7Po&t4EvH;wfgm~>i3&7m$$Fo`1+Mrx$?o{hx#U8 VlUcTarZUKAOav_Uyq#S?_!m_R4ru@Y literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..22588d03ef900718e19622e3cdc639d6a037312a GIT binary patch literal 3770 zcmbVOU2GIp6h6CK*cK>kY4{64ffPb4oe2ehpe3;MkA;g!GstR6BDCB6EQycV0=ImH7X{&_@X@cU^I%vbMEYPW=mbRHtE^9 zKj-Iu=R4=#tG8j1=farno=`l;HLMepE-UdV+dZXtTr0bVm{x377R63QGYxJD#Wr+J zp&1+)8WVu(!5}Ao{=(#jchyL^V_=YqqI}!)M?eBz+gQ&j*NRTY~#S z$vTc%Ik`OH#D!nRUmW=IRuU42ph*}d?g>_M(9Ein>@-u#!Y~!NvoLXzYa;(r)8N|D z*(*r^-vLNmdh4T)zridN=5rcCF&Ar4-F>H2*||T(4Hl&9EN;+Vps zQjlZcN#GxzXG@faC~MW^KzrvmymI5^H_nexEs}mSYPLk0$6U^F*UigEU!A%A!dQwb z7I*Y79IG}e3z?`MyW}vJ2|I=#nhm%>F|_&umOpFRwsST-s(=PMCAzN7l(1D3VW`@|fdr|uPPd{7z^oAk6?zK2^wv$osM5j`n=STF*5A>0T>Rm1RjrY~O|g=p@n!@!Ten9^{K72bXWh}+ z0qDxFroQAL-ta7JLNtNBa}^mHjPsoaauJcH->p(^yO&P1*iK?Qi4GD9iJc^Nk$9NI zBP1Rr@feBSB)Uj+li2G6GN6#_?UC0JO|>KRyXyu*LLciyKMSr671v*twTDz=MoAu^ z4dLys+iLif2@sz1m_lTmkcW7~dDtbOHMpRNjcU%qm!BmsDM?v9E9giEu?-1&kv-1L za)>T1NFeqKXf*T=xuGWHi%BJbjlLo%qclW7&rJxD-Gx1MBQT3AHB@Tr5wq}lQ3dRL zJW0v6L$8}8g&GAIaH3LqEdrJd_Y{uyjk}x$od~Cv22)e`*5UF_mfAV8Gbr)dSQDjm zwZjg%d99SyHJ+f2ozlZj`uuOsO6911U~B1awWMPAoF(imv{bXRkgxqxZy~jHoYd|U zCv6!eAxSdk1AX_AXqW!_XE%(|*P)t0L~N6rCEKL&D4BEE77MWgz>#@8)JY8ra7e1R O(C0A;w{*>Dtp5vq2bjbF literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken.serialized b/config/src/test/resources/serialized/6.5.x/org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..176b50cfeea3a45fcace81c4b95b151ad81e4ac7 GIT binary patch literal 756 zcmah{%}N|W5U!nFjk5TILcoKbOpp*}QF2>6Y$B*I;6fq+4?@pO?bBIDNb=6m2ef?cOz=$Q-G1T^LMmlY`NOiDh z=)kuabxHG)Z&a7}R^&{FNIs!8U5e0mQA}A!inU4owWet{o`k-b15AUNd;Q_v>X-+W z0IDjA(Axe5!%VQR4pl8tX}k8BUGsVX9VV!w4$`>xaq25sg(!s*TKuZ2EnDRK&y^Grz14p16I>d2wzXSeegKh$LzN}Euz z`WR&ZS-pz;=B~IZr5i8G-^1{^Q@&#ORQ extends AuthorizationEvent implements ResolvableTypeProvider { @Serial From 12a18c37922a986a3f0af3c382f21b01bbeb2a02 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 15:39:33 -0600 Subject: [PATCH 141/504] Polish Serialization Tests If Instancio fails to instatiate the class sample, it will now also delete the serialized sample file. Otherwise, it will leave a zero-byte file on the filesystem, confusing future test runs --- .../security/SpringSecurityCoreVersionSerializableTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index 64ff084274..1fb8aab8d5 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -775,10 +775,10 @@ class SpringSecurityCoreVersionSerializableTests { return; } Files.createFile(filePath); - Object instance = instancioWithDefaults(clazz).create(); - assertThat(instance).isInstanceOf(clazz); try (FileOutputStream fileOutputStream = new FileOutputStream(file); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) { + Object instance = instancioWithDefaults(clazz).create(); + assertThat(instance).isInstanceOf(clazz); objectOutputStream.writeObject(instance); objectOutputStream.flush(); } From 0220e471bba233b3bdf9bb72b89040a14eae7aa5 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 15:51:10 -0600 Subject: [PATCH 142/504] Move Serialization Samples To make SpringSecurityCoreVersionSerializableTests more manageable, this commit moves the sample class constructions to a separate file. In this way, the tests file only changes when serialization tests are added. When classes are introduced, they can be added to SerializationSamples, separating the two concerns --- .../security/SerializationSamples.java | 700 ++++++++++++++++++ ...gSecurityCoreVersionSerializableTests.java | 672 +---------------- ...zation.event.AuthorizationEvent.serialized | Bin 1603 -> 1581 bytes ...event.AuthorizationGrantedEvent.serialized | Bin 1692 -> 1670 bytes 4 files changed, 702 insertions(+), 670 deletions(-) create mode 100644 config/src/test/java/org/springframework/security/SerializationSamples.java diff --git a/config/src/test/java/org/springframework/security/SerializationSamples.java b/config/src/test/java/org/springframework/security/SerializationSamples.java new file mode 100644 index 0000000000..985b9633de --- /dev/null +++ b/config/src/test/java/org/springframework/security/SerializationSamples.java @@ -0,0 +1,700 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.time.Instant; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; + +import jakarta.servlet.http.Cookie; +import org.apereo.cas.client.validation.AssertionImpl; +import org.instancio.Instancio; +import org.instancio.InstancioApi; +import org.instancio.InstancioOfClassApi; +import org.instancio.Select; +import org.instancio.generator.Generator; + +import org.springframework.core.ResolvableType; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.AuthorizationServiceException; +import org.springframework.security.access.SecurityConfig; +import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException; +import org.springframework.security.access.intercept.RunAsUserToken; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.authentication.AccountExpiredException; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.authentication.LockedException; +import org.springframework.security.authentication.ProviderNotFoundException; +import org.springframework.security.authentication.RememberMeAuthenticationToken; +import org.springframework.security.authentication.TestAuthentication; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; +import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent; +import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent; +import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent; +import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent; +import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent; +import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent; +import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; +import org.springframework.security.authentication.event.LogoutSuccessEvent; +import org.springframework.security.authentication.jaas.JaasAuthenticationToken; +import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent; +import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent; +import org.springframework.security.authentication.ott.DefaultOneTimeToken; +import org.springframework.security.authentication.ott.InvalidOneTimeTokenException; +import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; +import org.springframework.security.authentication.password.CompromisedPasswordException; +import org.springframework.security.authorization.AuthorityAuthorizationDecision; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.security.authorization.event.AuthorizationEvent; +import org.springframework.security.authorization.event.AuthorizationGrantedEvent; +import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; +import org.springframework.security.cas.authentication.CasAuthenticationToken; +import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken; +import org.springframework.security.config.annotation.AlreadyBuiltException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.context.TransientSecurityContext; +import org.springframework.security.core.session.AbstractSessionEvent; +import org.springframework.security.core.session.ReactiveSessionInformation; +import org.springframework.security.core.session.SessionInformation; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.ldap.ppolicy.PasswordPolicyControl; +import org.springframework.security.ldap.ppolicy.PasswordPolicyErrorStatus; +import org.springframework.security.ldap.ppolicy.PasswordPolicyException; +import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl; +import org.springframework.security.ldap.userdetails.LdapAuthority; +import org.springframework.security.oauth2.client.ClientAuthorizationException; +import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken; +import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; +import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; +import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; +import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; +import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; +import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; +import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; +import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2AuthorizationException; +import org.springframework.security.oauth2.core.OAuth2DeviceCode; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; +import org.springframework.security.oauth2.core.OAuth2UserCode; +import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; +import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; +import org.springframework.security.oauth2.core.oidc.OidcIdToken; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.core.oidc.TestOidcIdTokens; +import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; +import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority; +import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; +import org.springframework.security.oauth2.core.user.TestOAuth2Users; +import org.springframework.security.oauth2.jwt.BadJwtException; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtDecoderInitializationException; +import org.springframework.security.oauth2.jwt.JwtEncodingException; +import org.springframework.security.oauth2.jwt.JwtException; +import org.springframework.security.oauth2.jwt.JwtValidationException; +import org.springframework.security.oauth2.jwt.TestJwts; +import org.springframework.security.oauth2.server.resource.BearerTokenError; +import org.springframework.security.oauth2.server.resource.BearerTokenErrors; +import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; +import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; +import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; +import org.springframework.security.saml2.Saml2Exception; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2X509Credential; +import org.springframework.security.saml2.credentials.TestSaml2X509Credentials; +import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken; +import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests; +import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; +import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; +import org.springframework.security.web.PortResolverImpl; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException; +import org.springframework.security.web.authentication.rememberme.CookieTheftException; +import org.springframework.security.web.authentication.rememberme.InvalidCookieException; +import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException; +import org.springframework.security.web.authentication.session.SessionAuthenticationException; +import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent; +import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent; +import org.springframework.security.web.authentication.www.NonceExpiredException; +import org.springframework.security.web.csrf.CsrfException; +import org.springframework.security.web.csrf.DefaultCsrfToken; +import org.springframework.security.web.csrf.InvalidCsrfTokenException; +import org.springframework.security.web.csrf.MissingCsrfTokenException; +import org.springframework.security.web.firewall.RequestRejectedException; +import org.springframework.security.web.savedrequest.DefaultSavedRequest; +import org.springframework.security.web.savedrequest.SimpleSavedRequest; +import org.springframework.security.web.server.firewall.ServerExchangeRejectedException; +import org.springframework.security.web.session.HttpSessionCreatedEvent; +import org.springframework.security.web.session.HttpSessionIdChangedEvent; +import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs; +import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs; +import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse; +import org.springframework.security.web.webauthn.api.AuthenticatorAttachment; +import org.springframework.security.web.webauthn.api.AuthenticatorTransport; +import org.springframework.security.web.webauthn.api.Bytes; +import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput; +import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput; +import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput; +import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs; +import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs; +import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.PublicKeyCredential; +import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor; +import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions; +import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; +import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses; +import org.springframework.security.web.webauthn.api.TestBytes; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.UserVerificationRequirement; +import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; +import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; +import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest; +import org.springframework.util.ReflectionUtils; + +final class SerializationSamples { + + static final Map, Generator> generatorByClassName = new HashMap<>(); + + static final Map, Supplier>> instancioByClassName = new HashMap<>(); + + static { + UserDetails user = TestAuthentication.user(); + Authentication authentication = TestAuthentication.authenticated(user); + SecurityContext securityContext = new SecurityContextImpl(authentication); + + // oauth2-core + generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create()); + generatorByClassName.put(OAuth2AuthorizationRequest.class, + (r) -> TestOAuth2AuthorizationRequests.request().build()); + generatorByClassName.put(OAuth2AuthorizationResponse.class, + (r) -> TestOAuth2AuthorizationResponses.success().build()); + generatorByClassName.put(OAuth2UserAuthority.class, (r) -> new OAuth2UserAuthority(Map.of("username", "user"))); + generatorByClassName.put(OAuth2AuthorizationExchange.class, (r) -> TestOAuth2AuthorizationExchanges.success()); + generatorByClassName.put(OidcUserInfo.class, (r) -> OidcUserInfo.builder().email("email@example.com").build()); + generatorByClassName.put(SessionInformation.class, + (r) -> new SessionInformation(user, r.alphanumeric(4), new Date(1704378933936L))); + generatorByClassName.put(ReactiveSessionInformation.class, + (r) -> new ReactiveSessionInformation(user, r.alphanumeric(4), Instant.ofEpochMilli(1704378933936L))); + generatorByClassName.put(OAuth2AccessToken.class, (r) -> TestOAuth2AccessTokens.scopes("scope")); + generatorByClassName.put(OAuth2DeviceCode.class, + (r) -> new OAuth2DeviceCode("token", Instant.now(), Instant.now())); + generatorByClassName.put(OAuth2RefreshToken.class, + (r) -> new OAuth2RefreshToken("refreshToken", Instant.now(), Instant.now())); + generatorByClassName.put(OAuth2UserCode.class, + (r) -> new OAuth2UserCode("token", Instant.now(), Instant.now())); + generatorByClassName.put(DefaultOidcUser.class, (r) -> TestOidcUsers.create()); + generatorByClassName.put(OidcUserAuthority.class, + (r) -> new OidcUserAuthority(TestOidcIdTokens.idToken().build(), + new OidcUserInfo(Map.of("claim", "value")), "claim")); + generatorByClassName.put(OAuth2AuthenticationException.class, + (r) -> new OAuth2AuthenticationException(new OAuth2Error("error", "description", "uri"), "message", + new RuntimeException())); + generatorByClassName.put(OAuth2AuthorizationException.class, + (r) -> new OAuth2AuthorizationException(new OAuth2Error("error", "description", "uri"), "message", + new RuntimeException())); + + // oauth2-client + ClientRegistration.Builder clientRegistrationBuilder = TestClientRegistrations.clientRegistration(); + ClientRegistration clientRegistration = clientRegistrationBuilder.build(); + WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId"); + generatorByClassName.put(ClientRegistration.class, (r) -> clientRegistration); + generatorByClassName.put(ClientRegistration.ProviderDetails.class, + (r) -> clientRegistration.getProviderDetails()); + generatorByClassName.put(ClientRegistration.ProviderDetails.UserInfoEndpoint.class, + (r) -> clientRegistration.getProviderDetails().getUserInfoEndpoint()); + generatorByClassName.put(ClientRegistration.Builder.class, (r) -> clientRegistrationBuilder); + generatorByClassName.put(OAuth2AuthorizedClient.class, + (r) -> new OAuth2AuthorizedClient(clientRegistration, "principal", TestOAuth2AccessTokens.noScopes())); + generatorByClassName.put(OAuth2LoginAuthenticationToken.class, (r) -> { + var token = new OAuth2LoginAuthenticationToken(clientRegistration, + TestOAuth2AuthorizationExchanges.success()); + token.setDetails(details); + return token; + }); + generatorByClassName.put(OAuth2AuthorizationCodeAuthenticationToken.class, (r) -> { + var token = TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated(); + token.setDetails(details); + return token; + }); + generatorByClassName.put(OAuth2AuthenticationToken.class, (r) -> { + var token = TestOAuth2AuthenticationTokens.authenticated(); + token.setDetails(details); + return token; + }); + generatorByClassName.put(OidcIdToken.class, (r) -> TestOidcIdTokens.idToken().build()); + generatorByClassName.put(OidcLogoutToken.class, + (r) -> TestOidcLogoutTokens.withSessionId("issuer", "sessionId").issuedAt(Instant.now()).build()); + generatorByClassName.put(OidcSessionInformation.class, (r) -> TestOidcSessionInformations.create()); + generatorByClassName.put(DefaultOAuth2AuthenticatedPrincipal.class, (r) -> { + OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active(); + return new DefaultOAuth2AuthenticatedPrincipal(principal.getName(), principal.getAttributes(), + (Collection) principal.getAuthorities()); + }); + generatorByClassName.put(ClientAuthorizationException.class, + (r) -> new ClientAuthorizationException(new OAuth2Error("error", "description", "uri"), "id", "message", + new RuntimeException())); + generatorByClassName.put(ClientAuthorizationRequiredException.class, + (r) -> new ClientAuthorizationRequiredException("id")); + + // oauth2-jose + generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException())); + generatorByClassName.put(JwtDecoderInitializationException.class, + (r) -> new JwtDecoderInitializationException("message", new RuntimeException())); + generatorByClassName.put(JwtEncodingException.class, + (r) -> new JwtEncodingException("message", new RuntimeException())); + generatorByClassName.put(JwtException.class, (r) -> new JwtException("message", new RuntimeException())); + generatorByClassName.put(JwtValidationException.class, + (r) -> new JwtValidationException("message", List.of(new OAuth2Error("error", "description", "uri")))); + + // oauth2-jwt + generatorByClassName.put(Jwt.class, (r) -> TestJwts.user()); + + // oauth2-resource-server + generatorByClassName + .put(org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.class, (r) -> { + var token = new org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken( + "token"); + token.setDetails(details); + return token; + }); + generatorByClassName.put(BearerTokenAuthenticationToken.class, (r) -> { + var token = new BearerTokenAuthenticationToken("token"); + token.setDetails(details); + return token; + }); + generatorByClassName.put(BearerTokenAuthentication.class, (r) -> { + var token = new BearerTokenAuthentication(TestOAuth2AuthenticatedPrincipals.active(), + TestOAuth2AccessTokens.noScopes(), user.getAuthorities()); + token.setDetails(details); + return token; + }); + generatorByClassName.put(JwtAuthenticationToken.class, (r) -> { + var token = new JwtAuthenticationToken(TestJwts.user()); + token.setDetails(details); + return token; + }); + generatorByClassName.put(BearerTokenError.class, (r) -> BearerTokenErrors.invalidToken("invalid token")); + generatorByClassName.put(OAuth2IntrospectionAuthenticatedPrincipal.class, + (r) -> TestOAuth2AuthenticatedPrincipals.active()); + generatorByClassName.put(InvalidBearerTokenException.class, + (r) -> new InvalidBearerTokenException("description", new RuntimeException())); + generatorByClassName.put(BadOpaqueTokenException.class, + (r) -> new BadOpaqueTokenException("message", new RuntimeException())); + generatorByClassName.put(OAuth2IntrospectionException.class, + (r) -> new OAuth2IntrospectionException("message", new RuntimeException())); + + // config + generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message")); + + // core + generatorByClassName.put(RunAsUserToken.class, (r) -> { + RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(), + AnonymousAuthenticationToken.class); + token.setDetails(details); + return token; + }); + generatorByClassName.put(RememberMeAuthenticationToken.class, (r) -> { + RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("key", user, user.getAuthorities()); + token.setDetails(details); + return token; + }); + generatorByClassName.put(UsernamePasswordAuthenticationToken.class, (r) -> { + var token = UsernamePasswordAuthenticationToken.unauthenticated(user, "creds"); + token.setDetails(details); + return token; + }); + generatorByClassName.put(JaasAuthenticationToken.class, (r) -> { + var token = new JaasAuthenticationToken(user, "creds", null); + token.setDetails(details); + return token; + }); + generatorByClassName.put(OneTimeTokenAuthenticationToken.class, + (r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token"))); + generatorByClassName.put(AccessDeniedException.class, + (r) -> new AccessDeniedException("access denied", new RuntimeException())); + generatorByClassName.put(AuthorizationServiceException.class, + (r) -> new AuthorizationServiceException("access denied", new RuntimeException())); + generatorByClassName.put(AccountExpiredException.class, + (r) -> new AccountExpiredException("error", new RuntimeException())); + generatorByClassName.put(AuthenticationCredentialsNotFoundException.class, + (r) -> new AuthenticationCredentialsNotFoundException("error", new RuntimeException())); + generatorByClassName.put(AuthenticationServiceException.class, + (r) -> new AuthenticationServiceException("error", new RuntimeException())); + generatorByClassName.put(BadCredentialsException.class, + (r) -> new BadCredentialsException("error", new RuntimeException())); + generatorByClassName.put(CredentialsExpiredException.class, + (r) -> new CredentialsExpiredException("error", new RuntimeException())); + generatorByClassName.put(DisabledException.class, + (r) -> new DisabledException("error", new RuntimeException())); + generatorByClassName.put(InsufficientAuthenticationException.class, + (r) -> new InsufficientAuthenticationException("error", new RuntimeException())); + generatorByClassName.put(InternalAuthenticationServiceException.class, + (r) -> new InternalAuthenticationServiceException("error", new RuntimeException())); + generatorByClassName.put(LockedException.class, (r) -> new LockedException("error", new RuntimeException())); + generatorByClassName.put(ProviderNotFoundException.class, (r) -> new ProviderNotFoundException("error")); + generatorByClassName.put(InvalidOneTimeTokenException.class, (r) -> new InvalidOneTimeTokenException("error")); + generatorByClassName.put(CompromisedPasswordException.class, + (r) -> new CompromisedPasswordException("error", new RuntimeException())); + generatorByClassName.put(UsernameNotFoundException.class, + (r) -> new UsernameNotFoundException("error", new RuntimeException())); + generatorByClassName.put(TestingAuthenticationToken.class, + (r) -> applyDetails(new TestingAuthenticationToken("username", "password"))); + generatorByClassName.put(AuthenticationFailureBadCredentialsEvent.class, + (r) -> new AuthenticationFailureBadCredentialsEvent(authentication, + new BadCredentialsException("message"))); + generatorByClassName.put(AuthenticationFailureCredentialsExpiredEvent.class, + (r) -> new AuthenticationFailureCredentialsExpiredEvent(authentication, + new CredentialsExpiredException("message"))); + generatorByClassName.put(AuthenticationFailureDisabledEvent.class, + (r) -> new AuthenticationFailureDisabledEvent(authentication, new DisabledException("message"))); + generatorByClassName.put(AuthenticationFailureExpiredEvent.class, + (r) -> new AuthenticationFailureExpiredEvent(authentication, new AccountExpiredException("message"))); + generatorByClassName.put(AuthenticationFailureLockedEvent.class, + (r) -> new AuthenticationFailureLockedEvent(authentication, new LockedException("message"))); + generatorByClassName.put(AuthenticationFailureProviderNotFoundEvent.class, + (r) -> new AuthenticationFailureProviderNotFoundEvent(authentication, + new ProviderNotFoundException("message"))); + generatorByClassName.put(AuthenticationFailureProxyUntrustedEvent.class, + (r) -> new AuthenticationFailureProxyUntrustedEvent(authentication, + new AuthenticationServiceException("message"))); + generatorByClassName.put(AuthenticationFailureServiceExceptionEvent.class, + (r) -> new AuthenticationFailureServiceExceptionEvent(authentication, + new AuthenticationServiceException("message"))); + generatorByClassName.put(AuthenticationSuccessEvent.class, + (r) -> new AuthenticationSuccessEvent(authentication)); + generatorByClassName.put(InteractiveAuthenticationSuccessEvent.class, + (r) -> new InteractiveAuthenticationSuccessEvent(authentication, Authentication.class)); + generatorByClassName.put(LogoutSuccessEvent.class, (r) -> new LogoutSuccessEvent(authentication)); + generatorByClassName.put(JaasAuthenticationFailedEvent.class, + (r) -> new JaasAuthenticationFailedEvent(authentication, new RuntimeException("message"))); + generatorByClassName.put(JaasAuthenticationSuccessEvent.class, + (r) -> new JaasAuthenticationSuccessEvent(authentication)); + generatorByClassName.put(AbstractSessionEvent.class, (r) -> new AbstractSessionEvent(securityContext)); + generatorByClassName.put(SecurityConfig.class, (r) -> new SecurityConfig("value")); + generatorByClassName.put(TransientSecurityContext.class, (r) -> new TransientSecurityContext(authentication)); + generatorByClassName.put(AuthorizationDeniedException.class, + (r) -> new AuthorizationDeniedException("message", new AuthorizationDecision(false))); + generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true)); + generatorByClassName.put(AuthorityAuthorizationDecision.class, + (r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER"))); + generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException()); + generatorByClassName.put(AuthorizationEvent.class, + (r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + generatorByClassName.put(AuthorizationGrantedEvent.class, + (r) -> new AuthorizationGrantedEvent<>(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + instancioByClassName.put(AuthorizationGrantedEvent.class, () -> { + InstancioOfClassApi instancio = Instancio.of(AuthorizationGrantedEvent.class); + instancio.withTypeParameters(String.class); + instancio.supply(Select.all(AuthorizationGrantedEvent.class), + generatorByClassName.get(AuthorizationGrantedEvent.class)); + return instancio; + }); + + // cas + generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> { + CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("creds"); + token.setDetails(details); + return token; + }); + generatorByClassName.put(CasAuthenticationToken.class, (r) -> { + var token = new CasAuthenticationToken("key", user, "Password", user.getAuthorities(), user, + new AssertionImpl("test")); + token.setDetails(details); + return token; + }); + generatorByClassName.put(CasAssertionAuthenticationToken.class, (r) -> { + var token = new CasAssertionAuthenticationToken(new AssertionImpl("test"), "ticket"); + token.setDetails(details); + return token; + }); + + // ldap + generatorByClassName.put(LdapAuthority.class, + (r) -> new LdapAuthority("USER", "username", Map.of("attribute", List.of("value1", "value2")))); + generatorByClassName.put(PasswordPolicyException.class, + (r) -> new PasswordPolicyException(PasswordPolicyErrorStatus.INSUFFICIENT_PASSWORD_QUALITY)); + generatorByClassName.put(PasswordPolicyControl.class, (r) -> new PasswordPolicyControl(true)); + generatorByClassName.put(PasswordPolicyResponseControl.class, (r) -> { + byte[] encodedResponse = { 0x30, 0x05, (byte) 0xA0, 0x03, (byte) 0xA0, 0x1, 0x21 }; + return new PasswordPolicyResponseControl(encodedResponse); + }); + + // saml2-service-provider + generatorByClassName.put(Saml2AuthenticationException.class, + (r) -> new Saml2AuthenticationException(new Saml2Error("code", "descirption"), "message", + new IOException("fail"))); + generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail"))); + generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class, + (r) -> TestSaml2Authentications.authentication().getPrincipal()); + generatorByClassName.put(Saml2Authentication.class, + (r) -> applyDetails(TestSaml2Authentications.authentication())); + generatorByClassName.put(Saml2PostAuthenticationRequest.class, + (r) -> TestSaml2PostAuthenticationRequests.create()); + generatorByClassName.put(Saml2RedirectAuthenticationRequest.class, + (r) -> TestSaml2RedirectAuthenticationRequests.create()); + generatorByClassName.put(Saml2X509Credential.class, + (r) -> TestSaml2X509Credentials.relyingPartyVerifyingCredential()); + generatorByClassName.put(RelyingPartyRegistration.AssertingPartyDetails.class, + (r) -> TestRelyingPartyRegistrations.full().build().getAssertingPartyMetadata()); + generatorByClassName.put(RelyingPartyRegistration.class, (r) -> TestRelyingPartyRegistrations.full().build()); + generatorByClassName.put(Saml2AuthenticationToken.class, (r) -> { + Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.tokenRequested(); + token.setDetails(details); + return token; + }); + generatorByClassName.put(Saml2LogoutRequest.class, (r) -> TestSaml2LogoutRequests.create()); + + // web + generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> { + Collection authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); + return applyDetails(new AnonymousAuthenticationToken("key", "username", authorities)); + }); + generatorByClassName.put(PreAuthenticatedAuthenticationToken.class, (r) -> { + PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(user, "creds", + user.getAuthorities()); + token.setDetails(details); + return token; + }); + generatorByClassName.put(PreAuthenticatedCredentialsNotFoundException.class, + (r) -> new PreAuthenticatedCredentialsNotFoundException("message", new IOException("fail"))); + generatorByClassName.put(CookieTheftException.class, (r) -> new CookieTheftException("message")); + generatorByClassName.put(InvalidCookieException.class, (r) -> new InvalidCookieException("message")); + generatorByClassName.put(RememberMeAuthenticationException.class, + (r) -> new RememberMeAuthenticationException("message", new IOException("fail"))); + generatorByClassName.put(SessionAuthenticationException.class, + (r) -> new SessionAuthenticationException("message")); + generatorByClassName.put(NonceExpiredException.class, + (r) -> new NonceExpiredException("message", new IOException("fail"))); + generatorByClassName.put(CsrfException.class, (r) -> new CsrfException("message")); + generatorByClassName.put(org.springframework.security.web.server.csrf.CsrfException.class, + (r) -> new org.springframework.security.web.server.csrf.CsrfException("message")); + generatorByClassName.put(InvalidCsrfTokenException.class, + (r) -> new InvalidCsrfTokenException(new DefaultCsrfToken("header", "parameter", "token"), "token")); + generatorByClassName.put(MissingCsrfTokenException.class, (r) -> new MissingCsrfTokenException("token")); + generatorByClassName.put(DefaultCsrfToken.class, (r) -> new DefaultCsrfToken("header", "parameter", "token")); + generatorByClassName.put(org.springframework.security.web.server.csrf.DefaultCsrfToken.class, + (r) -> new org.springframework.security.web.server.csrf.DefaultCsrfToken("header", "parameter", + "token")); + generatorByClassName.put(RequestRejectedException.class, (r) -> new RequestRejectedException("message")); + generatorByClassName.put(ServerExchangeRejectedException.class, + (r) -> new ServerExchangeRejectedException("message")); + generatorByClassName.put(SessionFixationProtectionEvent.class, + (r) -> new SessionFixationProtectionEvent(authentication, "old", "new")); + generatorByClassName.put(AuthenticationSwitchUserEvent.class, + (r) -> new AuthenticationSwitchUserEvent(authentication, user)); + generatorByClassName.put(HttpSessionCreatedEvent.class, + (r) -> new HttpSessionCreatedEvent(new MockHttpSession())); + generatorByClassName.put(SimpleSavedRequest.class, (r) -> { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/uri"); + request.setQueryString("query=string"); + request.setScheme("https"); + request.setServerName("localhost"); + request.setServerPort(80); + request.setRequestURI("/uri"); + request.setCookies(new Cookie("name", "value")); + request.addHeader("header", "value"); + request.addParameter("parameter", "value"); + request.setPathInfo("/path"); + request.addPreferredLocale(Locale.ENGLISH); + return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue")); + }); + generatorByClassName.put(HttpSessionIdChangedEvent.class, + (r) -> new HttpSessionIdChangedEvent(new MockHttpSession(), "1")); + + // webauthn + CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect( + CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL, + true); + Bytes id = TestBytes.get(); + AuthenticationExtensionsClientInputs inputs = new ImmutableAuthenticationExtensionsClientInputs( + ImmutableAuthenticationExtensionsClientInput.credProps); + // @formatter:off + PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder() + .id(id) + .type(PublicKeyCredentialType.PUBLIC_KEY) + .transports(Set.of(AuthenticatorTransport.USB)) + .build(); + // @formatter:on + generatorByClassName.put(AuthenticatorTransport.class, (a) -> AuthenticatorTransport.USB); + generatorByClassName.put(PublicKeyCredentialType.class, (k) -> PublicKeyCredentialType.PUBLIC_KEY); + generatorByClassName.put(UserVerificationRequirement.class, (r) -> UserVerificationRequirement.REQUIRED); + generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.CredProtect.class, (c) -> credProtect); + generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.class, + (c) -> new CredProtectAuthenticationExtensionsClientInput(credProtect)); + generatorByClassName.put(ImmutableAuthenticationExtensionsClientInputs.class, (i) -> inputs); + Field credPropsField = ReflectionUtils.findField(ImmutableAuthenticationExtensionsClientInput.class, + "credProps"); + generatorByClassName.put(credPropsField.getType(), + (i) -> ImmutableAuthenticationExtensionsClientInput.credProps); + generatorByClassName.put(Bytes.class, (b) -> id); + generatorByClassName.put(PublicKeyCredentialDescriptor.class, (d) -> descriptor); + // @formatter:off + generatorByClassName.put(PublicKeyCredentialRequestOptions.class, (o) -> TestPublicKeyCredentialRequestOptions.create() + .extensions(inputs) + .allowCredentials(List.of(descriptor)) + .build() + ); + + CredentialPropertiesOutput credentialOutput = new CredentialPropertiesOutput(false); + AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput); + AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse() + .build(); + PublicKeyCredential credential = TestPublicKeyCredential.createPublicKeyCredential( + response, outputs) + .build(); + RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest( + TestPublicKeyCredentialRequestOptions.create().build(), + credential + ); + WebAuthnAuthenticationRequestToken requestToken = new WebAuthnAuthenticationRequestToken(authRequest); + requestToken.setDetails(details); + generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput); + generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs); + generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response); + generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest); + generatorByClassName.put(PublicKeyCredential.class, (r) -> credential); + generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken); + generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM); + // @formatter:on + generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, + (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); + generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() + .id(TestBytes.get()) + .build(); + List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); + WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); + webAuthnAuthentication.setDetails(details); + return webAuthnAuthentication; + }); + // @formatter:on + generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class, + (r) -> new CredentialPropertiesOutput(true).getOutput()); + + // One-Time Token + DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user", + Instant.now().plusSeconds(300)); + generatorByClassName.put(DefaultOneTimeToken.class, (t) -> oneTimeToken); + } + + private SerializationSamples() { + + } + + static InstancioApi instancioWithDefaults(Class clazz) { + if (instancioByClassName.containsKey(clazz)) { + return instancioByClassName.get(clazz).get(); + } + InstancioOfClassApi instancio = Instancio.of(clazz); + ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics(); + for (ResolvableType type : generics) { + instancio.withTypeParameters(type.resolve()); + } + if (generatorByClassName.containsKey(clazz)) { + instancio.supply(Select.all(clazz), generatorByClassName.get(clazz)); + } + return instancio; + } + + private static T applyDetails(T authentication) { + WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId"); + authentication.setDetails(details); + return authentication; + } + + @SuppressWarnings("serial") + private static final class SerializableSupplier implements Supplier, Serializable { + + private final T value; + + SerializableSupplier(T value) { + this.value = value; + } + + @Override + public T get() { + return this.value; + } + + } + +} diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index 2712617475..a0bafbf58a 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -30,27 +30,12 @@ import java.lang.reflect.Modifier; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.Set; -import java.util.UUID; -import java.util.function.Supplier; import java.util.stream.Stream; -import jakarta.servlet.http.Cookie; -import org.apereo.cas.client.validation.AssertionImpl; -import org.instancio.Instancio; -import org.instancio.InstancioApi; -import org.instancio.InstancioOfClassApi; -import org.instancio.Select; -import org.instancio.generator.Generator; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -58,198 +43,8 @@ import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.ResolvableType; import org.springframework.core.type.filter.AssignableTypeFilter; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpSession; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.access.AuthorizationServiceException; -import org.springframework.security.access.SecurityConfig; -import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException; -import org.springframework.security.access.intercept.RunAsUserToken; -import org.springframework.security.authentication.AbstractAuthenticationToken; -import org.springframework.security.authentication.AccountExpiredException; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.CredentialsExpiredException; -import org.springframework.security.authentication.DisabledException; -import org.springframework.security.authentication.InsufficientAuthenticationException; -import org.springframework.security.authentication.InternalAuthenticationServiceException; -import org.springframework.security.authentication.LockedException; -import org.springframework.security.authentication.ProviderNotFoundException; -import org.springframework.security.authentication.RememberMeAuthenticationToken; -import org.springframework.security.authentication.TestAuthentication; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; -import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent; -import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent; -import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent; -import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent; -import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent; -import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent; -import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent; -import org.springframework.security.authentication.event.AuthenticationSuccessEvent; -import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; -import org.springframework.security.authentication.event.LogoutSuccessEvent; -import org.springframework.security.authentication.jaas.JaasAuthenticationToken; -import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent; -import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent; -import org.springframework.security.authentication.ott.DefaultOneTimeToken; -import org.springframework.security.authentication.ott.InvalidOneTimeTokenException; -import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; -import org.springframework.security.authentication.password.CompromisedPasswordException; -import org.springframework.security.authorization.AuthorityAuthorizationDecision; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationDeniedException; -import org.springframework.security.authorization.event.AuthorizationEvent; -import org.springframework.security.authorization.event.AuthorizationGrantedEvent; -import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; -import org.springframework.security.cas.authentication.CasAuthenticationToken; -import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken; -import org.springframework.security.config.annotation.AlreadyBuiltException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.core.context.TransientSecurityContext; -import org.springframework.security.core.session.AbstractSessionEvent; -import org.springframework.security.core.session.ReactiveSessionInformation; -import org.springframework.security.core.session.SessionInformation; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.ldap.ppolicy.PasswordPolicyControl; -import org.springframework.security.ldap.ppolicy.PasswordPolicyErrorStatus; -import org.springframework.security.ldap.ppolicy.PasswordPolicyException; -import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl; -import org.springframework.security.ldap.userdetails.LdapAuthority; -import org.springframework.security.oauth2.client.ClientAuthorizationException; -import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; -import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken; -import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; -import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; -import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; -import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; -import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; -import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; -import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.TestClientRegistrations; -import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.core.OAuth2AccessToken; -import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.OAuth2AuthorizationException; -import org.springframework.security.oauth2.core.OAuth2DeviceCode; -import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.oauth2.core.OAuth2RefreshToken; -import org.springframework.security.oauth2.core.OAuth2UserCode; -import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; -import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipals; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; -import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; -import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; -import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; -import org.springframework.security.oauth2.core.oidc.OidcIdToken; -import org.springframework.security.oauth2.core.oidc.OidcUserInfo; -import org.springframework.security.oauth2.core.oidc.TestOidcIdTokens; -import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; -import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority; -import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers; -import org.springframework.security.oauth2.core.user.DefaultOAuth2User; -import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; -import org.springframework.security.oauth2.core.user.TestOAuth2Users; -import org.springframework.security.oauth2.jwt.BadJwtException; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.JwtDecoderInitializationException; -import org.springframework.security.oauth2.jwt.JwtEncodingException; -import org.springframework.security.oauth2.jwt.JwtException; -import org.springframework.security.oauth2.jwt.JwtValidationException; -import org.springframework.security.oauth2.jwt.TestJwts; -import org.springframework.security.oauth2.server.resource.BearerTokenError; -import org.springframework.security.oauth2.server.resource.BearerTokenErrors; -import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; -import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; -import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; -import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; -import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; -import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; -import org.springframework.security.saml2.Saml2Exception; -import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2X509Credential; -import org.springframework.security.saml2.credentials.TestSaml2X509Credentials; -import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; -import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken; -import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; -import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; -import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens; -import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications; -import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests; -import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests; -import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests; -import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; -import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; -import org.springframework.security.web.PortResolverImpl; -import org.springframework.security.web.authentication.WebAuthenticationDetails; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException; -import org.springframework.security.web.authentication.rememberme.CookieTheftException; -import org.springframework.security.web.authentication.rememberme.InvalidCookieException; -import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException; -import org.springframework.security.web.authentication.session.SessionAuthenticationException; -import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent; -import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent; -import org.springframework.security.web.authentication.www.NonceExpiredException; -import org.springframework.security.web.csrf.CsrfException; -import org.springframework.security.web.csrf.DefaultCsrfToken; -import org.springframework.security.web.csrf.InvalidCsrfTokenException; -import org.springframework.security.web.csrf.MissingCsrfTokenException; -import org.springframework.security.web.firewall.RequestRejectedException; -import org.springframework.security.web.savedrequest.DefaultSavedRequest; -import org.springframework.security.web.savedrequest.SimpleSavedRequest; -import org.springframework.security.web.server.firewall.ServerExchangeRejectedException; -import org.springframework.security.web.session.HttpSessionCreatedEvent; -import org.springframework.security.web.session.HttpSessionIdChangedEvent; -import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs; -import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs; -import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse; -import org.springframework.security.web.webauthn.api.AuthenticatorAttachment; -import org.springframework.security.web.webauthn.api.AuthenticatorTransport; -import org.springframework.security.web.webauthn.api.Bytes; -import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput; -import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput; -import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput; -import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs; -import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs; -import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.PublicKeyCredential; -import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor; -import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.PublicKeyCredentialType; -import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses; -import org.springframework.security.web.webauthn.api.TestBytes; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.UserVerificationRequirement; -import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; -import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; -import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest; -import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -270,438 +65,12 @@ import static org.assertj.core.api.Assertions.fail; */ class SpringSecurityCoreVersionSerializableTests { - private static final Map, Generator> generatorByClassName = new HashMap<>(); - - private static final Map, Supplier>> instancioByClassName = new HashMap<>(); - static final long securitySerialVersionUid = SpringSecurityCoreVersion.SERIAL_VERSION_UID; static Path currentVersionFolder = Paths.get("src/test/resources/serialized/" + getCurrentVersion()); static Path previousVersionFolder = Paths.get("src/test/resources/serialized/" + getPreviousVersion()); - static { - UserDetails user = TestAuthentication.user(); - Authentication authentication = TestAuthentication.authenticated(user); - SecurityContext securityContext = new SecurityContextImpl(authentication); - - // oauth2-core - generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create()); - generatorByClassName.put(OAuth2AuthorizationRequest.class, - (r) -> TestOAuth2AuthorizationRequests.request().build()); - generatorByClassName.put(OAuth2AuthorizationResponse.class, - (r) -> TestOAuth2AuthorizationResponses.success().build()); - generatorByClassName.put(OAuth2UserAuthority.class, (r) -> new OAuth2UserAuthority(Map.of("username", "user"))); - generatorByClassName.put(OAuth2AuthorizationExchange.class, (r) -> TestOAuth2AuthorizationExchanges.success()); - generatorByClassName.put(OidcUserInfo.class, (r) -> OidcUserInfo.builder().email("email@example.com").build()); - generatorByClassName.put(SessionInformation.class, - (r) -> new SessionInformation(user, r.alphanumeric(4), new Date(1704378933936L))); - generatorByClassName.put(ReactiveSessionInformation.class, - (r) -> new ReactiveSessionInformation(user, r.alphanumeric(4), Instant.ofEpochMilli(1704378933936L))); - generatorByClassName.put(OAuth2AccessToken.class, (r) -> TestOAuth2AccessTokens.scopes("scope")); - generatorByClassName.put(OAuth2DeviceCode.class, - (r) -> new OAuth2DeviceCode("token", Instant.now(), Instant.now())); - generatorByClassName.put(OAuth2RefreshToken.class, - (r) -> new OAuth2RefreshToken("refreshToken", Instant.now(), Instant.now())); - generatorByClassName.put(OAuth2UserCode.class, - (r) -> new OAuth2UserCode("token", Instant.now(), Instant.now())); - generatorByClassName.put(DefaultOidcUser.class, (r) -> TestOidcUsers.create()); - generatorByClassName.put(OidcUserAuthority.class, - (r) -> new OidcUserAuthority(TestOidcIdTokens.idToken().build(), - new OidcUserInfo(Map.of("claim", "value")), "claim")); - generatorByClassName.put(OAuth2AuthenticationException.class, - (r) -> new OAuth2AuthenticationException(new OAuth2Error("error", "description", "uri"), "message", - new RuntimeException())); - generatorByClassName.put(OAuth2AuthorizationException.class, - (r) -> new OAuth2AuthorizationException(new OAuth2Error("error", "description", "uri"), "message", - new RuntimeException())); - - // oauth2-client - ClientRegistration.Builder clientRegistrationBuilder = TestClientRegistrations.clientRegistration(); - ClientRegistration clientRegistration = clientRegistrationBuilder.build(); - WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId"); - generatorByClassName.put(ClientRegistration.class, (r) -> clientRegistration); - generatorByClassName.put(ClientRegistration.ProviderDetails.class, - (r) -> clientRegistration.getProviderDetails()); - generatorByClassName.put(ClientRegistration.ProviderDetails.UserInfoEndpoint.class, - (r) -> clientRegistration.getProviderDetails().getUserInfoEndpoint()); - generatorByClassName.put(ClientRegistration.Builder.class, (r) -> clientRegistrationBuilder); - generatorByClassName.put(OAuth2AuthorizedClient.class, - (r) -> new OAuth2AuthorizedClient(clientRegistration, "principal", TestOAuth2AccessTokens.noScopes())); - generatorByClassName.put(OAuth2LoginAuthenticationToken.class, (r) -> { - var token = new OAuth2LoginAuthenticationToken(clientRegistration, - TestOAuth2AuthorizationExchanges.success()); - token.setDetails(details); - return token; - }); - generatorByClassName.put(OAuth2AuthorizationCodeAuthenticationToken.class, (r) -> { - var token = TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated(); - token.setDetails(details); - return token; - }); - generatorByClassName.put(OAuth2AuthenticationToken.class, (r) -> { - var token = TestOAuth2AuthenticationTokens.authenticated(); - token.setDetails(details); - return token; - }); - generatorByClassName.put(OidcIdToken.class, (r) -> TestOidcIdTokens.idToken().build()); - generatorByClassName.put(OidcLogoutToken.class, - (r) -> TestOidcLogoutTokens.withSessionId("issuer", "sessionId").issuedAt(Instant.now()).build()); - generatorByClassName.put(OidcSessionInformation.class, (r) -> TestOidcSessionInformations.create()); - generatorByClassName.put(DefaultOAuth2AuthenticatedPrincipal.class, (r) -> { - OAuth2AuthenticatedPrincipal principal = TestOAuth2AuthenticatedPrincipals.active(); - return new DefaultOAuth2AuthenticatedPrincipal(principal.getName(), principal.getAttributes(), - (Collection) principal.getAuthorities()); - }); - generatorByClassName.put(ClientAuthorizationException.class, - (r) -> new ClientAuthorizationException(new OAuth2Error("error", "description", "uri"), "id", "message", - new RuntimeException())); - generatorByClassName.put(ClientAuthorizationRequiredException.class, - (r) -> new ClientAuthorizationRequiredException("id")); - - // oauth2-jose - generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException())); - generatorByClassName.put(JwtDecoderInitializationException.class, - (r) -> new JwtDecoderInitializationException("message", new RuntimeException())); - generatorByClassName.put(JwtEncodingException.class, - (r) -> new JwtEncodingException("message", new RuntimeException())); - generatorByClassName.put(JwtException.class, (r) -> new JwtException("message", new RuntimeException())); - generatorByClassName.put(JwtValidationException.class, - (r) -> new JwtValidationException("message", List.of(new OAuth2Error("error", "description", "uri")))); - - // oauth2-jwt - generatorByClassName.put(Jwt.class, (r) -> TestJwts.user()); - - // oauth2-resource-server - generatorByClassName - .put(org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.class, (r) -> { - var token = new org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken( - "token"); - token.setDetails(details); - return token; - }); - generatorByClassName.put(BearerTokenAuthenticationToken.class, (r) -> { - var token = new BearerTokenAuthenticationToken("token"); - token.setDetails(details); - return token; - }); - generatorByClassName.put(BearerTokenAuthentication.class, (r) -> { - var token = new BearerTokenAuthentication(TestOAuth2AuthenticatedPrincipals.active(), - TestOAuth2AccessTokens.noScopes(), user.getAuthorities()); - token.setDetails(details); - return token; - }); - generatorByClassName.put(JwtAuthenticationToken.class, (r) -> { - var token = new JwtAuthenticationToken(TestJwts.user()); - token.setDetails(details); - return token; - }); - generatorByClassName.put(BearerTokenError.class, (r) -> BearerTokenErrors.invalidToken("invalid token")); - generatorByClassName.put(OAuth2IntrospectionAuthenticatedPrincipal.class, - (r) -> TestOAuth2AuthenticatedPrincipals.active()); - generatorByClassName.put(InvalidBearerTokenException.class, - (r) -> new InvalidBearerTokenException("description", new RuntimeException())); - generatorByClassName.put(BadOpaqueTokenException.class, - (r) -> new BadOpaqueTokenException("message", new RuntimeException())); - generatorByClassName.put(OAuth2IntrospectionException.class, - (r) -> new OAuth2IntrospectionException("message", new RuntimeException())); - - // config - generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message")); - - // core - generatorByClassName.put(RunAsUserToken.class, (r) -> { - RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(), - AnonymousAuthenticationToken.class); - token.setDetails(details); - return token; - }); - generatorByClassName.put(RememberMeAuthenticationToken.class, (r) -> { - RememberMeAuthenticationToken token = new RememberMeAuthenticationToken("key", user, user.getAuthorities()); - token.setDetails(details); - return token; - }); - generatorByClassName.put(UsernamePasswordAuthenticationToken.class, (r) -> { - var token = UsernamePasswordAuthenticationToken.unauthenticated(user, "creds"); - token.setDetails(details); - return token; - }); - generatorByClassName.put(JaasAuthenticationToken.class, (r) -> { - var token = new JaasAuthenticationToken(user, "creds", null); - token.setDetails(details); - return token; - }); - generatorByClassName.put(OneTimeTokenAuthenticationToken.class, - (r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token"))); - generatorByClassName.put(AccessDeniedException.class, - (r) -> new AccessDeniedException("access denied", new RuntimeException())); - generatorByClassName.put(AuthorizationServiceException.class, - (r) -> new AuthorizationServiceException("access denied", new RuntimeException())); - generatorByClassName.put(AccountExpiredException.class, - (r) -> new AccountExpiredException("error", new RuntimeException())); - generatorByClassName.put(AuthenticationCredentialsNotFoundException.class, - (r) -> new AuthenticationCredentialsNotFoundException("error", new RuntimeException())); - generatorByClassName.put(AuthenticationServiceException.class, - (r) -> new AuthenticationServiceException("error", new RuntimeException())); - generatorByClassName.put(BadCredentialsException.class, - (r) -> new BadCredentialsException("error", new RuntimeException())); - generatorByClassName.put(CredentialsExpiredException.class, - (r) -> new CredentialsExpiredException("error", new RuntimeException())); - generatorByClassName.put(DisabledException.class, - (r) -> new DisabledException("error", new RuntimeException())); - generatorByClassName.put(InsufficientAuthenticationException.class, - (r) -> new InsufficientAuthenticationException("error", new RuntimeException())); - generatorByClassName.put(InternalAuthenticationServiceException.class, - (r) -> new InternalAuthenticationServiceException("error", new RuntimeException())); - generatorByClassName.put(LockedException.class, (r) -> new LockedException("error", new RuntimeException())); - generatorByClassName.put(ProviderNotFoundException.class, (r) -> new ProviderNotFoundException("error")); - generatorByClassName.put(InvalidOneTimeTokenException.class, (r) -> new InvalidOneTimeTokenException("error")); - generatorByClassName.put(CompromisedPasswordException.class, - (r) -> new CompromisedPasswordException("error", new RuntimeException())); - generatorByClassName.put(UsernameNotFoundException.class, - (r) -> new UsernameNotFoundException("error", new RuntimeException())); - generatorByClassName.put(TestingAuthenticationToken.class, - (r) -> applyDetails(new TestingAuthenticationToken("username", "password"))); - generatorByClassName.put(AuthenticationFailureBadCredentialsEvent.class, - (r) -> new AuthenticationFailureBadCredentialsEvent(authentication, - new BadCredentialsException("message"))); - generatorByClassName.put(AuthenticationFailureCredentialsExpiredEvent.class, - (r) -> new AuthenticationFailureCredentialsExpiredEvent(authentication, - new CredentialsExpiredException("message"))); - generatorByClassName.put(AuthenticationFailureDisabledEvent.class, - (r) -> new AuthenticationFailureDisabledEvent(authentication, new DisabledException("message"))); - generatorByClassName.put(AuthenticationFailureExpiredEvent.class, - (r) -> new AuthenticationFailureExpiredEvent(authentication, new AccountExpiredException("message"))); - generatorByClassName.put(AuthenticationFailureLockedEvent.class, - (r) -> new AuthenticationFailureLockedEvent(authentication, new LockedException("message"))); - generatorByClassName.put(AuthenticationFailureProviderNotFoundEvent.class, - (r) -> new AuthenticationFailureProviderNotFoundEvent(authentication, - new ProviderNotFoundException("message"))); - generatorByClassName.put(AuthenticationFailureProxyUntrustedEvent.class, - (r) -> new AuthenticationFailureProxyUntrustedEvent(authentication, - new AuthenticationServiceException("message"))); - generatorByClassName.put(AuthenticationFailureServiceExceptionEvent.class, - (r) -> new AuthenticationFailureServiceExceptionEvent(authentication, - new AuthenticationServiceException("message"))); - generatorByClassName.put(AuthenticationSuccessEvent.class, - (r) -> new AuthenticationSuccessEvent(authentication)); - generatorByClassName.put(InteractiveAuthenticationSuccessEvent.class, - (r) -> new InteractiveAuthenticationSuccessEvent(authentication, Authentication.class)); - generatorByClassName.put(LogoutSuccessEvent.class, (r) -> new LogoutSuccessEvent(authentication)); - generatorByClassName.put(JaasAuthenticationFailedEvent.class, - (r) -> new JaasAuthenticationFailedEvent(authentication, new RuntimeException("message"))); - generatorByClassName.put(JaasAuthenticationSuccessEvent.class, - (r) -> new JaasAuthenticationSuccessEvent(authentication)); - generatorByClassName.put(AbstractSessionEvent.class, (r) -> new AbstractSessionEvent(securityContext)); - generatorByClassName.put(SecurityConfig.class, (r) -> new SecurityConfig("value")); - generatorByClassName.put(TransientSecurityContext.class, (r) -> new TransientSecurityContext(authentication)); - generatorByClassName.put(AuthorizationDeniedException.class, - (r) -> new AuthorizationDeniedException("message", new AuthorizationDecision(false))); - generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true)); - generatorByClassName.put(AuthorityAuthorizationDecision.class, - (r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER"))); - generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException()); - generatorByClassName.put(AuthorizationEvent.class, - (r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source", - new AuthorizationDecision(true))); - generatorByClassName.put(AuthorizationGrantedEvent.class, - (r) -> new AuthorizationGrantedEvent<>(new SerializableSupplier<>(authentication), "source", - new AuthorizationDecision(true))); - instancioByClassName.put(AuthorizationGrantedEvent.class, () -> { - InstancioOfClassApi instancio = Instancio.of(AuthorizationGrantedEvent.class); - instancio.withTypeParameters(String.class); - instancio.supply(Select.all(AuthorizationGrantedEvent.class), - generatorByClassName.get(AuthorizationGrantedEvent.class)); - return instancio; - }); - - // cas - generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> { - CasServiceTicketAuthenticationToken token = CasServiceTicketAuthenticationToken.stateless("creds"); - token.setDetails(details); - return token; - }); - generatorByClassName.put(CasAuthenticationToken.class, (r) -> { - var token = new CasAuthenticationToken("key", user, "Password", user.getAuthorities(), user, - new AssertionImpl("test")); - token.setDetails(details); - return token; - }); - generatorByClassName.put(CasAssertionAuthenticationToken.class, (r) -> { - var token = new CasAssertionAuthenticationToken(new AssertionImpl("test"), "ticket"); - token.setDetails(details); - return token; - }); - - // ldap - generatorByClassName.put(LdapAuthority.class, - (r) -> new LdapAuthority("USER", "username", Map.of("attribute", List.of("value1", "value2")))); - generatorByClassName.put(PasswordPolicyException.class, - (r) -> new PasswordPolicyException(PasswordPolicyErrorStatus.INSUFFICIENT_PASSWORD_QUALITY)); - generatorByClassName.put(PasswordPolicyControl.class, (r) -> new PasswordPolicyControl(true)); - generatorByClassName.put(PasswordPolicyResponseControl.class, (r) -> { - byte[] encodedResponse = { 0x30, 0x05, (byte) 0xA0, 0x03, (byte) 0xA0, 0x1, 0x21 }; - return new PasswordPolicyResponseControl(encodedResponse); - }); - - // saml2-service-provider - generatorByClassName.put(Saml2AuthenticationException.class, - (r) -> new Saml2AuthenticationException(new Saml2Error("code", "descirption"), "message", - new IOException("fail"))); - generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail"))); - generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class, - (r) -> TestSaml2Authentications.authentication().getPrincipal()); - generatorByClassName.put(Saml2Authentication.class, - (r) -> applyDetails(TestSaml2Authentications.authentication())); - generatorByClassName.put(Saml2PostAuthenticationRequest.class, - (r) -> TestSaml2PostAuthenticationRequests.create()); - generatorByClassName.put(Saml2RedirectAuthenticationRequest.class, - (r) -> TestSaml2RedirectAuthenticationRequests.create()); - generatorByClassName.put(Saml2X509Credential.class, - (r) -> TestSaml2X509Credentials.relyingPartyVerifyingCredential()); - generatorByClassName.put(AssertingPartyDetails.class, - (r) -> TestRelyingPartyRegistrations.full().build().getAssertingPartyMetadata()); - generatorByClassName.put(RelyingPartyRegistration.class, (r) -> TestRelyingPartyRegistrations.full().build()); - generatorByClassName.put(Saml2AuthenticationToken.class, (r) -> { - Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.tokenRequested(); - token.setDetails(details); - return token; - }); - generatorByClassName.put(Saml2LogoutRequest.class, (r) -> TestSaml2LogoutRequests.create()); - - // web - generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> { - Collection authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); - return applyDetails(new AnonymousAuthenticationToken("key", "username", authorities)); - }); - generatorByClassName.put(PreAuthenticatedAuthenticationToken.class, (r) -> { - PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(user, "creds", - user.getAuthorities()); - token.setDetails(details); - return token; - }); - generatorByClassName.put(PreAuthenticatedCredentialsNotFoundException.class, - (r) -> new PreAuthenticatedCredentialsNotFoundException("message", new IOException("fail"))); - generatorByClassName.put(CookieTheftException.class, (r) -> new CookieTheftException("message")); - generatorByClassName.put(InvalidCookieException.class, (r) -> new InvalidCookieException("message")); - generatorByClassName.put(RememberMeAuthenticationException.class, - (r) -> new RememberMeAuthenticationException("message", new IOException("fail"))); - generatorByClassName.put(SessionAuthenticationException.class, - (r) -> new SessionAuthenticationException("message")); - generatorByClassName.put(NonceExpiredException.class, - (r) -> new NonceExpiredException("message", new IOException("fail"))); - generatorByClassName.put(CsrfException.class, (r) -> new CsrfException("message")); - generatorByClassName.put(org.springframework.security.web.server.csrf.CsrfException.class, - (r) -> new org.springframework.security.web.server.csrf.CsrfException("message")); - generatorByClassName.put(InvalidCsrfTokenException.class, - (r) -> new InvalidCsrfTokenException(new DefaultCsrfToken("header", "parameter", "token"), "token")); - generatorByClassName.put(MissingCsrfTokenException.class, (r) -> new MissingCsrfTokenException("token")); - generatorByClassName.put(DefaultCsrfToken.class, (r) -> new DefaultCsrfToken("header", "parameter", "token")); - generatorByClassName.put(org.springframework.security.web.server.csrf.DefaultCsrfToken.class, - (r) -> new org.springframework.security.web.server.csrf.DefaultCsrfToken("header", "parameter", - "token")); - generatorByClassName.put(RequestRejectedException.class, (r) -> new RequestRejectedException("message")); - generatorByClassName.put(ServerExchangeRejectedException.class, - (r) -> new ServerExchangeRejectedException("message")); - generatorByClassName.put(SessionFixationProtectionEvent.class, - (r) -> new SessionFixationProtectionEvent(authentication, "old", "new")); - generatorByClassName.put(AuthenticationSwitchUserEvent.class, - (r) -> new AuthenticationSwitchUserEvent(authentication, user)); - generatorByClassName.put(HttpSessionCreatedEvent.class, - (r) -> new HttpSessionCreatedEvent(new MockHttpSession())); - generatorByClassName.put(SimpleSavedRequest.class, (r) -> { - MockHttpServletRequest request = new MockHttpServletRequest("GET", "/uri"); - request.setQueryString("query=string"); - request.setScheme("https"); - request.setServerName("localhost"); - request.setServerPort(80); - request.setRequestURI("/uri"); - request.setCookies(new Cookie("name", "value")); - request.addHeader("header", "value"); - request.addParameter("parameter", "value"); - request.setPathInfo("/path"); - request.addPreferredLocale(Locale.ENGLISH); - return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue")); - }); - generatorByClassName.put(HttpSessionIdChangedEvent.class, - (r) -> new HttpSessionIdChangedEvent(new MockHttpSession(), "1")); - - // webauthn - CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect( - CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL, - true); - Bytes id = TestBytes.get(); - AuthenticationExtensionsClientInputs inputs = new ImmutableAuthenticationExtensionsClientInputs( - ImmutableAuthenticationExtensionsClientInput.credProps); - // @formatter:off - PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder() - .id(id) - .type(PublicKeyCredentialType.PUBLIC_KEY) - .transports(Set.of(AuthenticatorTransport.USB)) - .build(); - // @formatter:on - generatorByClassName.put(AuthenticatorTransport.class, (a) -> AuthenticatorTransport.USB); - generatorByClassName.put(PublicKeyCredentialType.class, (k) -> PublicKeyCredentialType.PUBLIC_KEY); - generatorByClassName.put(UserVerificationRequirement.class, (r) -> UserVerificationRequirement.REQUIRED); - generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.CredProtect.class, (c) -> credProtect); - generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.class, - (c) -> new CredProtectAuthenticationExtensionsClientInput(credProtect)); - generatorByClassName.put(ImmutableAuthenticationExtensionsClientInputs.class, (i) -> inputs); - Field credPropsField = ReflectionUtils.findField(ImmutableAuthenticationExtensionsClientInput.class, - "credProps"); - generatorByClassName.put(credPropsField.getType(), - (i) -> ImmutableAuthenticationExtensionsClientInput.credProps); - generatorByClassName.put(Bytes.class, (b) -> id); - generatorByClassName.put(PublicKeyCredentialDescriptor.class, (d) -> descriptor); - // @formatter:off - generatorByClassName.put(PublicKeyCredentialRequestOptions.class, (o) -> TestPublicKeyCredentialRequestOptions.create() - .extensions(inputs) - .allowCredentials(List.of(descriptor)) - .build() - ); - - CredentialPropertiesOutput credentialOutput = new CredentialPropertiesOutput(false); - AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput); - AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse() - .build(); - PublicKeyCredential credential = TestPublicKeyCredential.createPublicKeyCredential( - response, outputs) - .build(); - RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest( - TestPublicKeyCredentialRequestOptions.create().build(), - credential - ); - WebAuthnAuthenticationRequestToken requestToken = new WebAuthnAuthenticationRequestToken(authRequest); - requestToken.setDetails(details); - generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput); - generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs); - generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response); - generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest); - generatorByClassName.put(PublicKeyCredential.class, (r) -> credential); - generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken); - generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM); - // @formatter:on - generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, - (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); - generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() - .id(TestBytes.get()) - .build(); - List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); - WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); - webAuthnAuthentication.setDetails(details); - return webAuthnAuthentication; - }); - // @formatter:on - generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class, - (r) -> new CredentialPropertiesOutput(true).getOutput()); - - // One-Time Token - DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user", - Instant.now().plusSeconds(300)); - generatorByClassName.put(DefaultOneTimeToken.class, (t) -> oneTimeToken); - } - @ParameterizedTest @MethodSource("getClassesToSerialize") @Disabled("This method should only be used to serialize the classes once") @@ -713,7 +82,7 @@ class SpringSecurityCoreVersionSerializableTests { return; } Files.createFile(filePath); - Object instance = instancioWithDefaults(clazz).create(); + Object instance = SerializationSamples.instancioWithDefaults(clazz).create(); assertThat(instance).isInstanceOf(clazz); try (FileOutputStream fileOutputStream = new FileOutputStream(file); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) { @@ -826,7 +195,7 @@ class SpringSecurityCoreVersionSerializableTests { } boolean matchesExpectedSerialVersion = ObjectStreamClass.lookup(clazz) .getSerialVersionUID() == securitySerialVersionUid; - boolean isUnderTest = generatorByClassName.containsKey(clazz); + boolean isUnderTest = SerializationSamples.generatorByClassName.containsKey(clazz); if (matchesExpectedSerialVersion || isUnderTest) { classes.add(clazz); } @@ -834,27 +203,6 @@ class SpringSecurityCoreVersionSerializableTests { return classes.stream(); } - private static InstancioApi instancioWithDefaults(Class clazz) { - if (instancioByClassName.containsKey(clazz)) { - return instancioByClassName.get(clazz).get(); - } - InstancioOfClassApi instancio = Instancio.of(clazz); - ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics(); - for (ResolvableType type : generics) { - instancio.withTypeParameters(type.resolve()); - } - if (generatorByClassName.containsKey(clazz)) { - instancio.supply(Select.all(clazz), generatorByClassName.get(clazz)); - } - return instancio; - } - - private static T applyDetails(T authentication) { - WebAuthenticationDetails details = new WebAuthenticationDetails("remote", "sessionId"); - authentication.setDetails(details); - return authentication; - } - private static String getCurrentVersion() { String version = System.getProperty("springSecurityVersion"); String[] parts = version.split("\\."); @@ -870,20 +218,4 @@ class SpringSecurityCoreVersionSerializableTests { return String.join(".", parts); } - @SuppressWarnings("serial") - private static final class SerializableSupplier implements Supplier, Serializable { - - private final T value; - - SerializableSupplier(T value) { - this.value = value; - } - - @Override - public T get() { - return this.value; - } - - } - } diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized index 568c4a3ac20bce16fcb82e8b004f27231125c6e3..be10e858ced14a1b4ff77dfb8a36d5090bc69433 100644 GIT binary patch delta 75 zcmX@ivzBLr3nRy(%x~?*MGS6}4>HRd2B#KfCgx;TC6;97=LIL`7UZNBtH1@5a#Dj! Y3kq^FQ;VJ@`bC_p?3nRzEPn?U2ix^@iA7GSq4=yOm%u5eWO)f3UEU9$PFG>wdEh^5;&kIg1 r%1q43tV&GENexLYE-6+)76~pbD9Fi7EeffU+P1onH)8WF#>p%IMJ6Uu diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized index 6d3ca9608f9cacaa523776a846715debb31b4d0c..74a66bf3b6068ce9de5aaf32aff951b9a471cd90 100644 GIT binary patch delta 74 zcmbQk+s3zy*_XQiDqi X3UV@2i=HL>nM7QiE4`VMX)+4{T6`UD delta 96 zcmZqUox{6fE+fanPn_$Dix^@iCd#@87ZhdYr3a@bmlkD~R66GurG}*z6=&w>1*aBe qCgx;TB_`#hhNKpk6ssVM1eX>R Date: Tue, 6 May 2025 15:29:20 +0700 Subject: [PATCH 143/504] Correct method name Closes gh-17031 Signed-off-by: Tran Ngoc Nhan --- docs/modules/ROOT/pages/servlet/authentication/logout.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/authentication/logout.adoc b/docs/modules/ROOT/pages/servlet/authentication/logout.adoc index f8219472ab..c971047ac7 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/logout.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/logout.adoc @@ -402,7 +402,7 @@ SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler(); @PostMapping("/my/logout") public String performLogout(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { // .. perform logout - this.logoutHandler.doLogout(request, response, authentication); + this.logoutHandler.logout(request, response, authentication); return "redirect:/home"; } ---- @@ -416,7 +416,7 @@ val logoutHandler = SecurityContextLogoutHandler() @PostMapping("/my/logout") fun performLogout(val authentication: Authentication, val request: HttpServletRequest, val response: HttpServletResponse): String { // .. perform logout - this.logoutHandler.doLogout(request, response, authentication) + this.logoutHandler.logout(request, response, authentication) return "redirect:/home" } ---- From a4111a606b846d52c687d50a285297e11541f557 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 03:13:37 +0000 Subject: [PATCH 144/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.5...v1.0.6) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b80f8aecc3..954255d36d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,7 +34,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.5" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.6" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 0c7e43a46276445f947a2b86d3365f2c42c128f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 03:26:38 +0000 Subject: [PATCH 145/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.5...v1.0.6) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f780f9621e..56d8410fd6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.5" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.6" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From dd0b26a9924185a2cc03ae58ee37d9267073869d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 03:35:25 +0000 Subject: [PATCH 146/504] Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6 Bumps [io.spring.gradle:spring-security-release-plugin](https://github.com/spring-io/spring-security-release-tools) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/spring-io/spring-security-release-tools/releases) - [Commits](https://github.com/spring-io/spring-security-release-tools/compare/v1.0.5...v1.0.6) --- updated-dependencies: - dependency-name: io.spring.gradle:spring-security-release-plugin dependency-version: 1.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2236a0cb2b..480783386d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } -io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.5" +io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.6" jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" From 6624e302ac0a7e8f89161659a8bf6d536aafccd8 Mon Sep 17 00:00:00 2001 From: Zhoudong Date: Tue, 11 Feb 2025 20:06:38 +0800 Subject: [PATCH 147/504] Favor Spring Framework NonNull over Reactor NonNull Signed-off-by: Zhoudong --- .../security/web/DefaultSecurityFilterChain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java b/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java index e643d77350..7117a7d1c7 100644 --- a/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java +++ b/web/src/main/java/org/springframework/security/web/DefaultSecurityFilterChain.java @@ -24,7 +24,6 @@ import jakarta.servlet.Filter; import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import reactor.util.annotation.NonNull; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -33,6 +32,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.log.LogMessage; +import org.springframework.lang.NonNull; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.StringUtils; From 184cd96ee6989168198e0007069dd4a49779ab30 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 11:56:07 -0600 Subject: [PATCH 148/504] Don't Update Minor Versions During RC Phase --- .github/dependabot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 73b02a7c52..79f1d99499 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -85,6 +85,7 @@ updates: - dependency-name: '*' update-types: - version-update:semver-major + - version-update:semver-minor - package-ecosystem: github-actions target-branch: 6.3.x From c385a59b68466d59a813f3d2f7744f30474abf5b Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:49:20 -0500 Subject: [PATCH 149/504] Improve SchemaZipPlugin Error Message Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .../io/spring/gradle/convention/SchemaZipPlugin.groovy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy index 3fccb2aef8..cb1fb3b8a4 100644 --- a/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy @@ -32,10 +32,13 @@ public class SchemaZipPlugin implements Plugin { for (def key : schemas.keySet()) { def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') assert shortName != key + def schemaResourceName = schemas.get(key) File xsdFile = module.sourceSets.main.resources.find { - it.path.endsWith(schemas.get(key)) + it.path.endsWith(schemaResourceName) + } + if (xsdFile == null) { + throw new IllegalStateException("Could not find schema file for resource name " + schemaResourceName + " in src/main/resources") } - assert xsdFile != null schemaZip.into (shortName) { duplicatesStrategy 'exclude' from xsdFile.path From 5abbcecccc1e0b1795f28eaa9dde02cc729145fe Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:48:50 -0500 Subject: [PATCH 150/504] Update to 7.0.0-SNAPSHOT Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- .github/dependabot.yml | 26 + .github/workflows/release-scheduler.yml | 2 +- .../config/SecurityNamespaceHandler.java | 4 +- .../main/resources/META-INF/spring.schemas | 6 +- .../security/config/spring-security-7.0.rnc | 1355 ++++++ .../security/config/spring-security-7.0.xsd | 3837 +++++++++++++++++ ...gSecurityCoreVersionSerializableTests.java | 6 + .../config/doc/XsdDocumentedTests.java | 6 +- ...ty.access.AccessDeniedException.serialized | Bin 0 -> 16530 bytes ...s.AuthorizationServiceException.serialized | Bin 0 -> 16610 bytes ....security.access.SecurityConfig.serialized | Bin 0 -> 109 bytes ...s.CycleInRoleHierarchyException.serialized | Bin 0 -> 11098 bytes ...access.intercept.RunAsUserToken.serialized | Bin 0 -> 1379 bytes ...ication.AccountExpiredException.serialized | Bin 0 -> 16839 bytes ...on.AnonymousAuthenticationToken.serialized | Bin 0 -> 787 bytes ...ionCredentialsNotFoundException.serialized | Bin 0 -> 16777 bytes ....AuthenticationServiceException.serialized | Bin 0 -> 16765 bytes ...ication.BadCredentialsException.serialized | Bin 0 -> 16758 bytes ...ion.CredentialsExpiredException.serialized | Bin 0 -> 16843 bytes ...uthentication.DisabledException.serialized | Bin 0 -> 16833 bytes ...fficientAuthenticationException.serialized | Bin 0 -> 16770 bytes ...lAuthenticationServiceException.serialized | Bin 0 -> 16862 bytes ....authentication.LockedException.serialized | Bin 0 -> 16831 bytes ...ation.ProviderNotFoundException.serialized | Bin 0 -> 11213 bytes ...n.RememberMeAuthenticationToken.serialized | Bin 0 -> 1200 bytes ...tion.TestingAuthenticationToken.serialized | Bin 0 -> 534 bytes ...namePasswordAuthenticationToken.serialized | Bin 0 -> 1118 bytes ...ationFailureBadCredentialsEvent.serialized | Bin 0 -> 11700 bytes ...nFailureCredentialsExpiredEvent.serialized | Bin 0 -> 11789 bytes ...henticationFailureDisabledEvent.serialized | Bin 0 -> 11769 bytes ...thenticationFailureExpiredEvent.serialized | Bin 0 -> 11774 bytes ...uthenticationFailureLockedEvent.serialized | Bin 0 -> 11765 bytes ...ionFailureProviderNotFoundEvent.serialized | Bin 0 -> 11704 bytes ...ationFailureProxyUntrustedEvent.serialized | Bin 0 -> 11707 bytes ...ionFailureServiceExceptionEvent.serialized | Bin 0 -> 11709 bytes ...vent.AuthenticationSuccessEvent.serialized | Bin 0 -> 304 bytes ...ctiveAuthenticationSuccessEvent.serialized | Bin 0 -> 414 bytes ...cation.event.LogoutSuccessEvent.serialized | Bin 0 -> 296 bytes ...on.jaas.JaasAuthenticationToken.serialized | Bin 0 -> 1205 bytes ...ation.jaas.JaasGrantedAuthority.serialized | Bin 0 -> 166 bytes ...t.JaasAuthenticationFailedEvent.serialized | Bin 0 -> 11326 bytes ....JaasAuthenticationSuccessEvent.serialized | Bin 0 -> 314 bytes ...ication.ott.DefaultOneTimeToken.serialized | Bin 0 -> 258 bytes ...tt.InvalidOneTimeTokenException.serialized | Bin 0 -> 11220 bytes ...OneTimeTokenAuthenticationToken.serialized | Bin 0 -> 699 bytes ...rd.CompromisedPasswordException.serialized | Bin 0 -> 16772 bytes ....AuthorityAuthorizationDecision.serialized | Bin 0 -> 400 bytes ...orization.AuthorizationDecision.serialized | Bin 0 -> 96 bytes ...on.AuthorizationDeniedException.serialized | Bin 0 -> 11307 bytes ...zation.event.AuthorizationEvent.serialized | Bin 0 -> 1581 bytes ...event.AuthorizationGrantedEvent.serialized | Bin 0 -> 1670 bytes ...CasAssertionAuthenticationToken.serialized | Bin 0 -> 1454 bytes ...tication.CasAuthenticationToken.serialized | Bin 0 -> 2094 bytes ...erviceTicketAuthenticationToken.serialized | Bin 0 -> 552 bytes ...nnotation.AlreadyBuiltException.serialized | Bin 0 -> 11073 bytes ...uthority.SimpleGrantedAuthority.serialized | Bin 0 -> 125 bytes ...ore.context.SecurityContextImpl.serialized | Bin 0 -> 153 bytes ...ontext.TransientSecurityContext.serialized | Bin 0 -> 1294 bytes ...re.session.AbstractSessionEvent.serialized | Bin 0 -> 198 bytes ...sion.ReactiveSessionInformation.serialized | Bin 0 -> 867 bytes ...core.session.SessionInformation.serialized | Bin 0 -> 849 bytes ...etails.User$AuthorityComparator.serialized | Bin 0 -> 91 bytes ....security.core.userdetails.User.serialized | Bin 0 -> 299 bytes ...tails.UsernameNotFoundException.serialized | Bin 0 -> 16762 bytes ...p.ppolicy.PasswordPolicyControl.serialized | Bin 0 -> 96 bytes ...ppolicy.PasswordPolicyException.serialized | Bin 0 -> 11328 bytes ...y.PasswordPolicyResponseControl.serialized | Bin 0 -> 506 bytes ....ldap.userdetails.InetOrgPerson.serialized | Bin 0 -> 1199 bytes ....ldap.userdetails.LdapAuthority.serialized | Bin 0 -> 265 bytes ...userdetails.LdapUserDetailsImpl.serialized | Bin 0 -> 401 bytes ...ecurity.ldap.userdetails.Person.serialized | Bin 0 -> 656 bytes ...nt.ClientAuthorizationException.serialized | Bin 0 -> 16940 bytes ...tAuthorizationRequiredException.serialized | Bin 0 -> 11626 bytes ...2.client.OAuth2AuthorizedClient.serialized | Bin 0 -> 3455 bytes ...client.OAuth2AuthorizedClientId.serialized | Bin 0 -> 171 bytes ...ation.OAuth2AuthenticationToken.serialized | Bin 0 -> 1657 bytes ...rizationCodeAuthenticationToken.serialized | Bin 0 -> 5546 bytes ....OAuth2LoginAuthenticationToken.serialized | Bin 0 -> 5624 bytes ...2AuthorizedClientRefreshedEvent.serialized | Bin 0 -> 3632 bytes ...on.event.OidcUserRefreshedEvent.serialized | Bin 0 -> 3770 bytes ...tication.logout.OidcLogoutToken.serialized | Bin 0 -> 895 bytes ....session.OidcSessionInformation.serialized | Bin 0 -> 2430 bytes ...tion.ClientRegistration$Builder.serialized | Bin 0 -> 1845 bytes ...ientRegistration$ClientSettings.serialized | Bin 0 -> 129 bytes ...registration.ClientRegistration.serialized | Bin 0 -> 2471 bytes ...auth2.core.AuthenticationMethod.serialized | Bin 0 -> 123 bytes ...th2.core.AuthorizationGrantType.serialized | Bin 0 -> 121 bytes ...core.ClientAuthenticationMethod.serialized | Bin 0 -> 126 bytes ...ultOAuth2AuthenticatedPrincipal.serialized | Bin 0 -> 1225 bytes ...ore.OAuth2AccessToken$TokenType.serialized | Bin 0 -> 126 bytes ...y.oauth2.core.OAuth2AccessToken.serialized | Bin 0 -> 733 bytes ...e.OAuth2AuthenticationException.serialized | Bin 0 -> 16972 bytes ...re.OAuth2AuthorizationException.serialized | Bin 0 -> 16821 bytes ...ty.oauth2.core.OAuth2DeviceCode.serialized | Bin 0 -> 313 bytes ...ecurity.oauth2.core.OAuth2Error.serialized | Bin 0 -> 159 bytes ....oauth2.core.OAuth2RefreshToken.serialized | Bin 0 -> 322 bytes ...rity.oauth2.core.OAuth2UserCode.serialized | Bin 0 -> 311 bytes ...int.OAuth2AuthorizationExchange.serialized | Bin 0 -> 2008 bytes ...oint.OAuth2AuthorizationRequest.serialized | Bin 0 -> 1469 bytes ...int.OAuth2AuthorizationResponse.serialized | Bin 0 -> 462 bytes ...OAuth2AuthorizationResponseType.serialized | Bin 0 -> 140 bytes ...ty.oauth2.core.oidc.OidcIdToken.serialized | Bin 0 -> 682 bytes ...y.oauth2.core.oidc.OidcUserInfo.serialized | Bin 0 -> 328 bytes ....core.oidc.user.DefaultOidcUser.serialized | Bin 0 -> 2051 bytes ...ore.oidc.user.OidcUserAuthority.serialized | Bin 0 -> 1313 bytes ...th2.core.user.DefaultOAuth2User.serialized | Bin 0 -> 968 bytes ...2.core.user.OAuth2UserAuthority.serialized | Bin 0 -> 417 bytes ...rity.oauth2.jwt.BadJwtException.serialized | Bin 0 -> 16587 bytes ...amework.security.oauth2.jwt.Jwt.serialized | Bin 0 -> 831 bytes ...tDecoderInitializationException.serialized | Bin 0 -> 16540 bytes ...oauth2.jwt.JwtEncodingException.serialized | Bin 0 -> 16594 bytes ...ecurity.oauth2.jwt.JwtException.serialized | Bin 0 -> 16519 bytes ...uth2.jwt.JwtValidationException.serialized | Bin 0 -> 11427 bytes ....BearerTokenAuthenticationToken.serialized | Bin 0 -> 781 bytes ...erver.resource.BearerTokenError.serialized | Bin 0 -> 473 bytes ...rce.InvalidBearerTokenException.serialized | Bin 0 -> 17355 bytes ...ation.BearerTokenAuthentication.serialized | Bin 0 -> 3022 bytes ....BearerTokenAuthenticationToken.serialized | Bin 0 -> 684 bytes ...ication.DPoPAuthenticationToken.serialized | Bin 0 -> 756 bytes ...tication.JwtAuthenticationToken.serialized | Bin 0 -> 1554 bytes ...pection.BadOpaqueTokenException.serialized | Bin 0 -> 16665 bytes ...ospectionAuthenticatedPrincipal.serialized | Bin 0 -> 1434 bytes ...on.OAuth2IntrospectionException.serialized | Bin 0 -> 16561 bytes ...curity.provisioning.MutableUser.serialized | Bin 0 -> 190 bytes ...k.security.saml2.Saml2Exception.serialized | Bin 0 -> 16611 bytes ....security.saml2.core.Saml2Error.serialized | Bin 0 -> 145 bytes ....saml2.core.Saml2X509Credential.serialized | Bin 0 -> 1623 bytes ...aultSaml2AuthenticatedPrincipal.serialized | Bin 0 -> 357 bytes ...hentication.Saml2Authentication.serialized | Bin 0 -> 1187 bytes ...on.Saml2AuthenticationException.serialized | Bin 0 -> 17070 bytes ...cation.Saml2AuthenticationToken.serialized | Bin 0 -> 6302 bytes ....Saml2PostAuthenticationRequest.serialized | Bin 0 -> 417 bytes ...l2RedirectAuthenticationRequest.serialized | Bin 0 -> 473 bytes ...ation.logout.Saml2LogoutRequest.serialized | Bin 0 -> 736 bytes ...istration$AssertingPartyDetails.serialized | Bin 0 -> 2621 bytes ...ration.RelyingPartyRegistration.serialized | Bin 0 -> 5860 bytes ...UnreachableFilterChainException.serialized | Bin 0 -> 759 bytes ...cation.WebAuthenticationDetails.serialized | Bin 0 -> 162 bytes ...uthenticatedAuthenticationToken.serialized | Bin 0 -> 1231 bytes ...tedCredentialsNotFoundException.serialized | Bin 0 -> 16834 bytes ...oritiesWebAuthenticationDetails.serialized | Bin 0 -> 385 bytes ...rememberme.CookieTheftException.serialized | Bin 0 -> 11333 bytes ...memberme.InvalidCookieException.serialized | Bin 0 -> 11335 bytes ...memberMeAuthenticationException.serialized | Bin 0 -> 16826 bytes ....SessionAuthenticationException.serialized | Bin 0 -> 11233 bytes ....SessionFixationProtectionEvent.serialized | Bin 0 -> 382 bytes ...r.AuthenticationSwitchUserEvent.serialized | Bin 0 -> 1016 bytes ...user.SwitchUserGrantedAuthority.serialized | Bin 0 -> 203 bytes ...ation.www.NonceExpiredException.serialized | Bin 0 -> 16807 bytes ...security.web.csrf.CsrfException.serialized | Bin 0 -> 11077 bytes ...urity.web.csrf.DefaultCsrfToken.serialized | Bin 0 -> 172 bytes ....csrf.InvalidCsrfTokenException.serialized | Bin 0 -> 11241 bytes ....csrf.MissingCsrfTokenException.serialized | Bin 0 -> 11227 bytes ...rewall.RequestRejectedException.serialized | Bin 0 -> 11020 bytes ...avedrequest.DefaultSavedRequest.serialized | Bin 0 -> 1787 bytes ...ty.web.savedrequest.SavedCookie.serialized | Bin 0 -> 250 bytes ...savedrequest.SimpleSavedRequest.serialized | Bin 0 -> 1022 bytes ...y.web.server.csrf.CsrfException.serialized | Bin 0 -> 11084 bytes ...eb.server.csrf.DefaultCsrfToken.serialized | Bin 0 -> 179 bytes ...ServerExchangeRejectedException.serialized | Bin 0 -> 11034 bytes ...session.HttpSessionCreatedEvent.serialized | Bin 0 -> 354 bytes ...ssion.HttpSessionIdChangedEvent.serialized | Bin 0 -> 421 bytes ....AuthenticatorAssertionResponse.serialized | Bin 0 -> 783 bytes ...thn.api.AuthenticatorAttachment.serialized | Bin 0 -> 130 bytes ...uthn.api.AuthenticatorTransport.serialized | Bin 0 -> 124 bytes ...security.web.webauthn.api.Bytes.serialized | Bin 0 -> 140 bytes ...tensionsClientInput$CredProtect.serialized | Bin 0 -> 507 bytes ...enticationExtensionsClientInput.serialized | Bin 0 -> 733 bytes ...ropertiesOutput$ExtensionOutput.serialized | Bin 0 -> 115 bytes ....api.CredentialPropertiesOutput.serialized | Bin 0 -> 306 bytes ...enticationExtensionsClientInput.serialized | Bin 0 -> 230 bytes ...nticationExtensionsClientInputs.serialized | Bin 0 -> 540 bytes ...ticationExtensionsClientOutputs.serialized | Bin 0 -> 619 bytes ...lePublicKeyCredentialUserEntity.serialized | Bin 0 -> 361 bytes ...ebauthn.api.PublicKeyCredential.serialized | Bin 0 -> 2288 bytes ...i.PublicKeyCredentialDescriptor.serialized | Bin 0 -> 688 bytes ...blicKeyCredentialRequestOptions.serialized | Bin 0 -> 1833 bytes ...thn.api.PublicKeyCredentialType.serialized | Bin 0 -> 132 bytes ...api.UserVerificationRequirement.serialized | Bin 0 -> 134 bytes ...tication.WebAuthnAuthentication.serialized | Bin 0 -> 1185 bytes ...AuthnAuthenticationRequestToken.serialized | Bin 0 -> 4101 bytes ...lyingPartyAuthenticationRequest.serialized | Bin 0 -> 3406 bytes .../servlet/appendix/namespace/index.adoc | 2 +- docs/modules/ROOT/pages/whats-new.adoc | 30 +- git/hooks/prepare-forward-merge | 2 +- gradle.properties | 2 +- .../src/main/resources/META-INF/security.tld | 2 +- 187 files changed, 5240 insertions(+), 40 deletions(-) create mode 100644 config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc create mode 100644 config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.access.AccessDeniedException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.access.AuthorizationServiceException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.access.SecurityConfig.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.access.intercept.RunAsUserToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AccountExpiredException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AuthenticationCredentialsNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AuthenticationServiceException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.BadCredentialsException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.CredentialsExpiredException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.DisabledException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.LockedException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ProviderNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureLockedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.JaasGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.DefaultOneTimeToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.InvalidOneTimeTokenException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorityAuthorizationDecision.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDecision.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.SecurityContextImpl.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.TransientSecurityContext.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.AbstractSessionEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.SessionInformation.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.User$AuthorityComparator.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.User.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.InetOrgPerson.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.Person.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.ClientAuthorizationRequiredException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClient.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClientId.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$Builder.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$ClientSettings.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.AuthorizationGrantType.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AccessToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2DeviceCode.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2Error.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2RefreshToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2UserCode.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.OidcIdToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.user.DefaultOAuth2User.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.Jwt.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtDecoderInitializationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.InvalidBearerTokenException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.provisioning.MutableUser.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.Saml2Exception.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.core.Saml2Error.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.core.Saml2X509Credential.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.UnreachableFilterChainException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.InvalidCookieException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.session.SessionFixationProtectionEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.CsrfException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.DefaultCsrfToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.firewall.RequestRejectedException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SavedCookie.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.server.csrf.CsrfException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.server.csrf.DefaultCsrfToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.server.firewall.ServerExchangeRejectedException.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorTransport.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.Bytes.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput$CredProtect.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialType.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.UserVerificationRequirement.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest.serialized diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 79f1d99499..86a24961f5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,32 @@ registries: type: maven-repository url: https://repo.spring.io/milestone updates: + - package-ecosystem: gradle + target-branch: 6.5.x + directory: / + schedule: + interval: daily + time: '03:00' + timezone: Etc/UTC + labels: + - 'type: dependency-upgrade' + registries: + - spring-milestones + ignore: + - dependency-name: com.nimbusds:nimbus-jose-jwt + - dependency-name: org.python:jython + - dependency-name: org.apache.directory.server:* + - dependency-name: org.apache.directory.shared:* + - dependency-name: org.junit:junit-bom + update-types: + - version-update:semver-major + - dependency-name: org.mockito:mockito-bom + update-types: + - version-update:semver-major + - dependency-name: '*' + update-types: + - version-update:semver-major + - version-update:semver-minor - package-ecosystem: gradle target-branch: 6.4.x directory: / diff --git a/.github/workflows/release-scheduler.yml b/.github/workflows/release-scheduler.yml index 8b2f0f1eac..9f0045ba1e 100644 --- a/.github/workflows/release-scheduler.yml +++ b/.github/workflows/release-scheduler.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: # List of active maintenance branches. - branch: [ main, 6.4.x, 6.3.x ] + branch: [ main, 6.5.x, 6.4.x, 6.3.x ] runs-on: ubuntu-latest steps: - name: Checkout diff --git a/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java b/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java index 0baa1e2dc6..7f39e23b6d 100644 --- a/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java +++ b/config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java @@ -96,7 +96,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler { pc.getReaderContext() .fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or " + "spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema " - + "with Spring Security 6.5. Please update your schema declarations to the 6.5 schema.", + + "with Spring Security 7.0. Please update your schema declarations to the 7.0 schema.", element); } String name = pc.getDelegate().getLocalName(element); @@ -221,7 +221,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler { private boolean matchesVersionInternal(Element element) { String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"); - return schemaLocation.matches("(?m).*spring-security-6\\.5.*.xsd.*") + return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*") || schemaLocation.matches("(?m).*spring-security.xsd.*") || !schemaLocation.matches("(?m).*spring-security.*"); } diff --git a/config/src/main/resources/META-INF/spring.schemas b/config/src/main/resources/META-INF/spring.schemas index bd7429a36c..d32871d3c8 100644 --- a/config/src/main/resources/META-INF/spring.schemas +++ b/config/src/main/resources/META-INF/spring.schemas @@ -14,7 +14,8 @@ # limitations under the License. # -http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd +http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd +http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd http\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd http\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd @@ -41,7 +42,8 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd -https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-6.5.xsd +https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd +https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd https\://www.springframework.org/schema/security/spring-security-6.3.xsd=org/springframework/security/config/spring-security-6.3.xsd diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc new file mode 100644 index 0000000000..ec51246b6f --- /dev/null +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -0,0 +1,1355 @@ +namespace a = "https://relaxng.org/ns/compatibility/annotations/1.0" +datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" + +default namespace = "http://www.springframework.org/schema/security" + +start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider + +hash = + ## Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + attribute hash {"bcrypt"} +base64 = + ## Whether a string should be base64 encoded + attribute base64 {xsd:boolean} +request-matcher = + ## Defines the strategy use for matching incoming requests. Currently the options are 'mvc' (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions and 'ciRegex' for case-insensitive regular expressions. + attribute request-matcher {"mvc" | "ant" | "regex" | "ciRegex"} +port = + ## Specifies an IP port number. Used to configure an embedded LDAP server, for example. + attribute port { xsd:nonNegativeInteger } +url = + ## Specifies a URL. + attribute url { xsd:token } +id = + ## A bean identifier, used for referring to the bean elsewhere in the context. + attribute id {xsd:token} +name = + ## A bean identifier, used for referring to the bean elsewhere in the context. + attribute name {xsd:token} +ref = + ## Defines a reference to a Spring bean Id. + attribute ref {xsd:token} + +cache-ref = + ## Defines a reference to a cache for use with a UserDetailsService. + attribute cache-ref {xsd:token} + +user-service-ref = + ## A reference to a user-service (or UserDetailsService bean) Id + attribute user-service-ref {xsd:token} + +authentication-manager-ref = + ## A reference to an AuthenticationManager bean + attribute authentication-manager-ref {xsd:token} + +data-source-ref = + ## A reference to a DataSource bean + attribute data-source-ref {xsd:token} + + + +debug = + ## Enables Spring Security debugging infrastructure. This will provide human-readable (multi-line) debugging information to monitor requests coming into the security filters. This may include sensitive information, such as request parameters or headers, and should only be used in a development environment. + element debug {empty} + +password-encoder = + ## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example. + element password-encoder {password-encoder.attlist} +password-encoder.attlist &= + ref | (hash) + +role-prefix = + ## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. + attribute role-prefix {xsd:token} + +use-expressions = + ## Enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. Defaults to 'true'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. + attribute use-expressions {xsd:boolean} + +ldap-server = + ## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied. + element ldap-server {ldap-server.attlist} +ldap-server.attlist &= id? +ldap-server.attlist &= (url | port)? +ldap-server.attlist &= + ## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used. + attribute manager-dn {xsd:string}? +ldap-server.attlist &= + ## The password for the manager DN. This is required if the manager-dn is specified. + attribute manager-password {xsd:string}? +ldap-server.attlist &= + ## Explicitly specifies an ldif file resource to load into an embedded LDAP server. The default is classpath*:*.ldiff + attribute ldif { xsd:string }? +ldap-server.attlist &= + ## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org" + attribute root { xsd:string }? +ldap-server.attlist &= + ## Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and 'unboundid'. By default, it will depends if the library is available in the classpath. + attribute mode { "apacheds" | "unboundid" }? + +ldap-server-ref-attribute = + ## The optional server to use. If omitted, and a default LDAP server is registered (using with no Id), that server will be used. + attribute server-ref {xsd:token} + + +group-search-filter-attribute = + ## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + attribute group-search-filter {xsd:token} +group-search-base-attribute = + ## Search base for group membership searches. Defaults to "" (searching from the root). + attribute group-search-base {xsd:token} +user-search-filter-attribute = + ## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name. + attribute user-search-filter {xsd:token} +user-search-base-attribute = + ## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + attribute user-search-base {xsd:token} +group-role-attribute-attribute = + ## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + attribute group-role-attribute {xsd:token} +user-details-class-attribute = + ## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object + attribute user-details-class {"person" | "inetOrgPerson"} +user-context-mapper-attribute = + ## Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry + attribute user-context-mapper-ref {xsd:token} + + +ldap-user-service = + ## This element configures a LdapUserDetailsService which is a combination of a FilterBasedLdapUserSearch and a DefaultLdapAuthoritiesPopulator. + element ldap-user-service {ldap-us.attlist} +ldap-us.attlist &= id? +ldap-us.attlist &= + ldap-server-ref-attribute? +ldap-us.attlist &= + user-search-filter-attribute? +ldap-us.attlist &= + user-search-base-attribute? +ldap-us.attlist &= + group-search-filter-attribute? +ldap-us.attlist &= + group-search-base-attribute? +ldap-us.attlist &= + group-role-attribute-attribute? +ldap-us.attlist &= + cache-ref? +ldap-us.attlist &= + role-prefix? +ldap-us.attlist &= + (user-details-class-attribute | user-context-mapper-attribute)? + +ldap-authentication-provider = + ## Sets up an ldap authentication provider + element ldap-authentication-provider {ldap-ap.attlist, password-compare-element?} +ldap-ap.attlist &= + ldap-server-ref-attribute? +ldap-ap.attlist &= + user-search-base-attribute? +ldap-ap.attlist &= + user-search-filter-attribute? +ldap-ap.attlist &= + group-search-base-attribute? +ldap-ap.attlist &= + group-search-filter-attribute? +ldap-ap.attlist &= + group-role-attribute-attribute? +ldap-ap.attlist &= + ## A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username. + attribute user-dn-pattern {xsd:token}? +ldap-ap.attlist &= + role-prefix? +ldap-ap.attlist &= + (user-details-class-attribute | user-context-mapper-attribute)? + +password-compare-element = + ## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user + element password-compare {password-compare.attlist, password-encoder?} + +password-compare.attlist &= + ## The attribute in the directory which contains the user password. Defaults to "userPassword". + attribute password-attribute {xsd:token}? +password-compare.attlist &= + hash? + +intercept-methods = + ## Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods + element intercept-methods {intercept-methods.attlist, protect+} +intercept-methods.attlist &= + ## Optional AccessDecisionManager bean ID to be used by the created method security interceptor. + attribute access-decision-manager-ref {xsd:token}? +intercept-methods.attlist &= + ## Use the AuthorizationManager API instead of AccessDecisionManager (defaults to true) + attribute use-authorization-manager {xsd:boolean}? +intercept-methods.attlist &= + ## Use this AuthorizationManager instead of the default (supercedes use-authorization-manager) + attribute authorization-manager-ref {xsd:token}? + +protect = + ## Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security". + element protect {protect.attlist, empty} +protect.attlist &= + ## A method name + attribute method {xsd:token} +protect.attlist &= + ## Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B". + attribute access {xsd:token} + +method-security-metadata-source = + ## Creates a MethodSecurityMetadataSource instance + element method-security-metadata-source {msmds.attlist, protect+} +msmds.attlist &= id? + +msmds.attlist &= use-expressions? + +method-security = + ## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with Spring Security annotations. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. Interceptors are invoked in the order specified in AuthorizationInterceptorsOrder. Use can create your own interceptors using Spring AOP. Also, annotation-based interception can be overridden by expressions listed in elements. + element method-security {method-security.attlist, expression-handler?, protect-pointcut*} +method-security.attlist &= + ## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "true". + attribute pre-post-enabled {xsd:boolean}? +method-security.attlist &= + ## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "false". + attribute secured-enabled {xsd:boolean}? +method-security.attlist &= + ## Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "false". + attribute jsr250-enabled {xsd:boolean}? +method-security.attlist &= + ## If true, class-based proxying will be used instead of interface-based proxying. + attribute proxy-target-class {xsd:boolean}? +method-security.attlist &= + ## If set to aspectj, then use AspectJ to intercept method invocation + attribute mode {"aspectj"}? +method-security.attlist &= + ## Specifies the security context holder strategy to use, by default uses a ThreadLocal-based strategy + attribute security-context-holder-strategy-ref {xsd:string}? +method-security.attlist &= + ## Use this ObservationRegistry to collect metrics on various parts of the filter chain + attribute observation-registry-ref {xsd:token}? + +global-method-security = + ## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250. + element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*} +global-method-security.attlist &= + ## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled". + attribute pre-post-annotations {"disabled" | "enabled" }? +global-method-security.attlist &= + ## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled". + attribute secured-annotations {"disabled" | "enabled" }? +global-method-security.attlist &= + ## Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled". + attribute jsr250-annotations {"disabled" | "enabled" }? +global-method-security.attlist &= + ## Optional AccessDecisionManager bean ID to override the default used for method security. + attribute access-decision-manager-ref {xsd:token}? +global-method-security.attlist &= + ## Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor + attribute run-as-manager-ref {xsd:token}? +global-method-security.attlist &= + ## Allows the advice "order" to be set for the method security interceptor. + attribute order {xsd:token}? +global-method-security.attlist &= + ## If true, class based proxying will be used instead of interface based proxying. + attribute proxy-target-class {xsd:boolean}? +global-method-security.attlist &= + ## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module. + attribute mode {"aspectj"}? +global-method-security.attlist &= + ## An external MethodSecurityMetadataSource instance can be supplied which will take priority over other sources (such as the default annotations). + attribute metadata-source-ref {xsd:token}? +global-method-security.attlist &= + authentication-manager-ref? + + +after-invocation-provider = + ## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security. + element after-invocation-provider {ref} + +pre-post-annotation-handling = + ## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled. + element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice} + +invocation-attribute-factory = + ## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods. + element invocation-attribute-factory {ref} + +pre-invocation-advice = + ## Customizes the PreInvocationAuthorizationAdviceVoter with the ref as the PreInvocationAuthorizationAdviceVoter for the element. + element pre-invocation-advice {ref} + +post-invocation-advice = + ## Customizes the PostInvocationAdviceProvider with the ref as the PostInvocationAuthorizationAdvice for the element. + element post-invocation-advice {ref} + + +expression-handler = + ## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied. + element expression-handler {ref} + +protect-pointcut = + ## Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization. + element protect-pointcut {protect-pointcut.attlist, empty} +protect-pointcut.attlist &= + ## An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes). + attribute expression {xsd:string} +protect-pointcut.attlist &= + ## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B" + attribute access {xsd:token} + +websocket-message-broker = + ## Allows securing a Message Broker. There are two modes. If no id is specified: ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that can be manually registered with the clientInboundChannel. + element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message* & expression-handler?) } + +websocket-message-broker.attrlist &= + ## A bean identifier, used for referring to the bean elsewhere in the context. If specified, explicit configuration within clientInboundChannel is required. If not specified, ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. + attribute id {xsd:token}? +websocket-message-broker.attrlist &= + ## Disables the requirement for CSRF token to be present in the Stomp headers (default false). Changing the default is useful if it is necessary to allow other origins to make SockJS connections. + attribute same-origin-disabled {xsd:boolean}? +websocket-message-broker.attrlist &= + ## Use this AuthorizationManager instead of deriving one from elements + attribute authorization-manager-ref {xsd:string}? +websocket-message-broker.attrlist &= + ## Use AuthorizationManager API instead of SecurityMetadatasource (defaults to true) + attribute use-authorization-manager {xsd:boolean}? +websocket-message-broker.attrlist &= + ## Use this SecurityContextHolderStrategy (note only supported in conjunction with the AuthorizationManager API) + attribute security-context-holder-strategy-ref {xsd:string}? + +intercept-message = + ## Creates an authorization rule for a websocket message. + element intercept-message {intercept-message.attrlist} + +intercept-message.attrlist &= + ## The destination ant pattern which will be mapped to the access attribute. For example, /** matches any message with a destination, /admin/** matches any message that has a destination that starts with admin. + attribute pattern {xsd:token}? +intercept-message.attrlist &= + ## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'. + attribute access {xsd:token}? +intercept-message.attrlist &= + ## The type of message to match on. Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER). + attribute type {"CONNECT" | "CONNECT_ACK" | "HEARTBEAT" | "MESSAGE" | "SUBSCRIBE"| "UNSUBSCRIBE" | "DISCONNECT" | "DISCONNECT_ACK" | "OTHER"}? + +http-firewall = + ## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace. + element http-firewall {ref} + +http = + ## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none". + element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & oauth2-login? & oauth2-client? & oauth2-resource-server? & saml2-login? & saml2-logout? & x509? & jee? & http-basic? & logout? & password-management? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) } +http.attlist &= + ## The request URL pattern which will be mapped to the filter chain created by this element. If omitted, the filter chain will match all requests. + attribute pattern {xsd:token}? +http.attlist &= + ## When set to 'none', requests matching the pattern attribute will be ignored by Spring Security. No security filters will be applied and no SecurityContext will be available. If set, the element must be empty, with no children. + attribute security {"none"}? +http.attlist &= + ## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + attribute request-matcher-ref { xsd:token }? +http.attlist &= + ## Optional attribute specifying the ID of the RequestMatcher implementation used to decide whether to redirect a request to HTTPS + attribute redirect-to-https-request-matcher-ref { xsd:token }? +http.attlist &= + ## A legacy attribute which automatically registers a login form, BASIC authentication and a logout URL and logout services. If unspecified, defaults to "false". We'd recommend you avoid using this and instead explicitly configure the services you require. + attribute auto-config {xsd:boolean}? +http.attlist &= + use-expressions? +http.attlist &= + ## A reference to a SecurityContextHolderStrategy bean. This can be used to customize how the SecurityContextHolder is stored during a request + attribute security-context-holder-strategy-ref {xsd:token}? +http.attlist &= + ## Controls the eagerness with which an HTTP session is created by Spring Security classes. If not set, defaults to "ifRequired". If "stateless" is used, this implies that the application guarantees that it will not create a session. This differs from the use of "never" which means that Spring Security will not create a session, but will make use of one if the application does. + attribute create-session {"ifRequired" | "always" | "never" | "stateless"}? +http.attlist &= + ## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests. + attribute security-context-repository-ref {xsd:token}? +http.attlist &= + ## Optional attribute that specifies that the SecurityContext should require explicit saving rather than being synchronized from the SecurityContextHolder. Defaults to "true". + attribute security-context-explicit-save {xsd:boolean}? +http.attlist &= + request-matcher? +http.attlist &= + ## Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true". + attribute servlet-api-provision {xsd:boolean}? +http.attlist &= + ## If available, runs the request as the Subject acquired from the JaasAuthenticationToken. Defaults to "false". + attribute jaas-api-provision {xsd:boolean}? +http.attlist &= + ## Use AuthorizationManager API instead of SecurityMetadataSource (defaults to true) + attribute use-authorization-manager {xsd:boolean}? +http.attlist &= + ## Use this AuthorizationManager instead of deriving one from elements + attribute authorization-manager-ref {xsd:token}? +http.attlist &= + ## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests. + attribute access-decision-manager-ref {xsd:token}? +http.attlist &= + ## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application". + attribute realm {xsd:token}? +http.attlist &= + ## Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter. + attribute entry-point-ref {xsd:token}? +http.attlist &= + ## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "false" + attribute once-per-request {xsd:boolean}? +http.attlist &= + ## Corresponds to the shouldFilterAllDispatcherTypes property of AuthorizationFilter. Do not work when use-authorization-manager=false. Defaults to "true". + attribute filter-all-dispatcher-types {xsd:boolean}? +http.attlist &= + ## Prevents the jsessionid parameter from being added to rendered URLs. Defaults to "true" (rewriting is disabled). + attribute disable-url-rewriting {xsd:boolean}? +http.attlist &= + ## Exposes the list of filters defined by this configuration under this bean name in the application context. + name? +http.attlist &= + authentication-manager-ref? +http.attlist &= + ## Use this ObservationRegistry to collect metrics on various parts of the filter chain + attribute observation-registry-ref {xsd:token}? + +access-denied-handler = + ## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance. + element access-denied-handler {access-denied-handler.attlist, empty} +access-denied-handler.attlist &= (ref | access-denied-handler-page) + +access-denied-handler-page = + ## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. + attribute error-page {xsd:token} + +intercept-url = + ## Specifies the access attributes and/or filter list for a particular set of URLs. + element intercept-url {intercept-url.attlist, empty} +intercept-url.attlist &= + (pattern | request-matcher-ref) +intercept-url.attlist &= + ## The access configuration attributes that apply for the configured path. + attribute access {xsd:token}? +intercept-url.attlist &= + ## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method. + attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH" | "TRACE"}? + +intercept-url.attlist &= + ## Used to specify that a URL must be accessed over http or https, or that there is no preference. The value should be "http", "https" or "any", respectively. + attribute requires-channel {xsd:token}? +intercept-url.attlist &= + ## The path to the servlet. This attribute is only applicable when 'request-matcher' is 'mvc'. In addition, the value is only required in the following 2 use cases: 1) There are 2 or more HttpServlet's registered in the ServletContext that have mappings starting with '/' and are different; 2) The pattern starts with the same value of a registered HttpServlet path, excluding the default (root) HttpServlet '/'. + attribute servlet-path {xsd:token}? + +logout = + ## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic. + element logout {logout.attlist, empty} +logout.attlist &= + ## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /logout if unspecified. + attribute logout-url {xsd:token}? +logout.attlist &= + ## Specifies the URL to display once the user has logged out. If not specified, defaults to /?logout (i.e. /login?logout). + attribute logout-success-url {xsd:token}? +logout.attlist &= + ## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true. + attribute invalidate-session {xsd:boolean}? +logout.attlist &= + ## A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out. + attribute success-handler-ref {xsd:token}? +logout.attlist &= + ## A comma-separated list of the names of cookies which should be deleted when the user logs out + attribute delete-cookies {xsd:token}? + +request-cache = + ## Allow the RequestCache used for saving requests during the login process to be set + element request-cache {ref} + +form-login = + ## Sets up a form login configuration for authentication with a username and password + element form-login {form-login.attlist, empty} +form-login.attlist &= + ## The URL that the login form is posted to. If unspecified, it defaults to /login. + attribute login-processing-url {xsd:token}? +form-login.attlist &= + ## The name of the request parameter which contains the username. Defaults to 'username'. + attribute username-parameter {xsd:token}? +form-login.attlist &= + ## The name of the request parameter which contains the password. Defaults to 'password'. + attribute password-parameter {xsd:token}? +form-login.attlist &= + ## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application. + attribute default-target-url {xsd:token}? +form-login.attlist &= + ## Whether the user should always be redirected to the default-target-url after login. + attribute always-use-default-target {xsd:boolean}? +form-login.attlist &= + ## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at GET /login and a corresponding filter to render that login URL when requested. + attribute login-page {xsd:token}? +form-login.attlist &= + ## The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /login?error and a corresponding filter to render that login failure URL when requested. + attribute authentication-failure-url {xsd:token}? +form-login.attlist &= + ## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. Should not be used in combination with default-target-url (or always-use-default-target-url) as the implementation should always deal with navigation to the subsequent destination + attribute authentication-success-handler-ref {xsd:token}? +form-login.attlist &= + ## Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination + attribute authentication-failure-handler-ref {xsd:token}? +form-login.attlist &= + ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter + attribute authentication-details-source-ref {xsd:token}? +form-login.attlist &= + ## The URL for the ForwardAuthenticationFailureHandler + attribute authentication-failure-forward-url {xsd:token}? +form-login.attlist &= + ## The URL for the ForwardAuthenticationSuccessHandler + attribute authentication-success-forward-url {xsd:token}? + +oauth2-login = + ## Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. + element oauth2-login {oauth2-login.attlist} +oauth2-login.attlist &= + ## Reference to the ClientRegistrationRepository + attribute client-registration-repository-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OAuth2AuthorizedClientRepository + attribute authorized-client-repository-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OAuth2AuthorizedClientService + attribute authorized-client-service-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the AuthorizationRequestRepository + attribute authorization-request-repository-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OAuth2AuthorizationRequestResolver + attribute authorization-request-resolver-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the authorization RedirectStrategy + attribute authorization-redirect-strategy-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OAuth2AccessTokenResponseClient + attribute access-token-response-client-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the GrantedAuthoritiesMapper + attribute user-authorities-mapper-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OAuth2UserService + attribute user-service-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the OpenID Connect OAuth2UserService + attribute oidc-user-service-ref {xsd:token}? +oauth2-login.attlist &= + ## The URI where the filter processes authentication requests + attribute login-processing-url {xsd:token}? +oauth2-login.attlist &= + ## The URI to send users to login + attribute login-page {xsd:token}? +oauth2-login.attlist &= + ## Reference to the AuthenticationSuccessHandler + attribute authentication-success-handler-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the AuthenticationFailureHandler + attribute authentication-failure-handler-ref {xsd:token}? +oauth2-login.attlist &= + ## Reference to the JwtDecoderFactory used by OidcAuthorizationCodeAuthenticationProvider + attribute jwt-decoder-factory-ref {xsd:token}? + +oauth2-client = + ## Configures OAuth 2.0 Client support. + element oauth2-client {oauth2-client.attlist, (authorization-code-grant?) } +oauth2-client.attlist &= + ## Reference to the ClientRegistrationRepository + attribute client-registration-repository-ref {xsd:token}? +oauth2-client.attlist &= + ## Reference to the OAuth2AuthorizedClientRepository + attribute authorized-client-repository-ref {xsd:token}? +oauth2-client.attlist &= + ## Reference to the OAuth2AuthorizedClientService + attribute authorized-client-service-ref {xsd:token}? + +authorization-code-grant = + ## Configures OAuth 2.0 Authorization Code Grant. + element authorization-code-grant {authorization-code-grant.attlist, empty} +authorization-code-grant.attlist &= + ## Reference to the AuthorizationRequestRepository + attribute authorization-request-repository-ref {xsd:token}? +authorization-code-grant.attlist &= + ## Reference to the authorization RedirectStrategy + attribute authorization-redirect-strategy-ref {xsd:token}? +authorization-code-grant.attlist &= + ## Reference to the OAuth2AuthorizationRequestResolver + attribute authorization-request-resolver-ref {xsd:token}? +authorization-code-grant.attlist &= + ## Reference to the OAuth2AccessTokenResponseClient + attribute access-token-response-client-ref {xsd:token}? + +client-registrations = + ## Container element for client(s) registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. + element client-registrations {client-registration+, provider*} + +client-registration = + ## Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. + element client-registration {client-registration.attlist} +client-registration.attlist &= + ## The ID that uniquely identifies the client registration. + attribute registration-id {xsd:token} +client-registration.attlist &= + ## The client identifier. + attribute client-id {xsd:token} +client-registration.attlist &= + ## The client secret. + attribute client-secret {xsd:token}? +client-registration.attlist &= + ## The method used to authenticate the client with the provider. The supported values are client_secret_basic, client_secret_post and none (public clients). + attribute client-authentication-method {"client_secret_basic" | "basic" | "client_secret_post" | "post" | "none"}? +client-registration.attlist &= + ## The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The supported values are authorization_code, client_credentials and password. + attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password"}? +client-registration.attlist &= + ## The client’s registered redirect URI that the Authorization Server redirects the end-user’s user-agent to after the end-user has authenticated and authorized access to the client. + attribute redirect-uri {xsd:token}? +client-registration.attlist &= + ## A comma-separated list of scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. + attribute scope {xsd:token}? +client-registration.attlist &= + ## A descriptive name used for the client. The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. + attribute client-name {xsd:token}? +client-registration.attlist &= + ## A reference to the associated provider. May reference a 'provider' element or use one of the common providers (google, github, facebook, okta). + attribute provider-id {xsd:token} + +provider = + ## The configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. + element provider {provider.attlist} +provider.attlist &= + ## The ID that uniquely identifies the provider. + attribute provider-id {xsd:token} +provider.attlist &= + ## The Authorization Endpoint URI for the Authorization Server. + attribute authorization-uri {xsd:token}? +provider.attlist &= + ## The Token Endpoint URI for the Authorization Server. + attribute token-uri {xsd:token}? +provider.attlist &= + ## The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user. + attribute user-info-uri {xsd:token}? +provider.attlist &= + ## The authentication method used when sending the access token to the UserInfo Endpoint. The supported values are header, form and query. + attribute user-info-authentication-method {"header" | "form" | "query"}? +provider.attlist &= + ## The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. + attribute user-info-user-name-attribute {xsd:token}? +provider.attlist &= + ## The URI used to retrieve the JSON Web Key (JWK) Set from the Authorization Server, which contains the cryptographic key(s) used to verify the JSON Web Signature (JWS) of the ID Token and optionally the UserInfo Response. + attribute jwk-set-uri {xsd:token}? +provider.attlist &= + ## The URI used to discover the configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. + attribute issuer-uri {xsd:token}? + +oauth2-resource-server = + ## Configures authentication support as an OAuth 2.0 Resource Server. + element oauth2-resource-server {oauth2-resource-server.attlist, (jwt? & opaque-token?)} +oauth2-resource-server.attlist &= + ## Reference to an AuthenticationManagerResolver + attribute authentication-manager-resolver-ref {xsd:token}? +oauth2-resource-server.attlist &= + ## Reference to a BearerTokenResolver + attribute bearer-token-resolver-ref {xsd:token}? +oauth2-resource-server.attlist &= + ## Reference to a AuthenticationEntryPoint + attribute entry-point-ref {xsd:token}? + +jwt = + ## Configures JWT authentication + element jwt {jwt.attlist} +jwt.attlist &= + ## The URI to use to collect the JWK Set for verifying JWTs + attribute jwk-set-uri {xsd:token}? +jwt.attlist &= + ## Reference to a JwtDecoder + attribute decoder-ref {xsd:token}? +jwt.attlist &= + ## Reference to a Converter + attribute jwt-authentication-converter-ref {xsd:token}? + +opaque-token = + ## Configuration Opaque Token authentication + element opaque-token {opaque-token.attlist} +opaque-token.attlist &= + ## The URI to use to introspect opaque token attributes + attribute introspection-uri {xsd:token}? +opaque-token.attlist &= + ## The Client ID to use to authenticate the introspection request + attribute client-id {xsd:token}? +opaque-token.attlist &= + ## The Client secret to use to authenticate the introspection request + attribute client-secret {xsd:token}? +opaque-token.attlist &= + ## Reference to an OpaqueTokenIntrospector + attribute introspector-ref {xsd:token}? +opaque-token.attlist &= + ## Reference to an OpaqueTokenAuthenticationConverter responsible for converting successful introspection result into an Authentication. + attribute authentication-converter-ref {xsd:token}? + +saml2-login = + ## Configures authentication support for SAML 2.0 Login + element saml2-login {saml2-login.attlist} +saml2-login.attlist &= + ## Reference to the RelyingPartyRegistrationRepository + attribute relying-party-registration-repository-ref {xsd:token}? +saml2-login.attlist &= + ## Reference to the Saml2AuthenticationRequestRepository + attribute authentication-request-repository-ref {xsd:token}? +saml2-login.attlist &= + ## Reference to the Saml2AuthenticationRequestResolver + attribute authentication-request-resolver-ref {xsd:token}? +saml2-login.attlist &= + ## Reference to the AuthenticationConverter + attribute authentication-converter-ref {xsd:token}? +saml2-login.attlist &= + ## The URI where the filter processes authentication requests + attribute login-processing-url {xsd:token}? +saml2-login.attlist &= + ## The URI to send users to login + attribute login-page {xsd:token}? +saml2-login.attlist &= + ## Reference to the AuthenticationSuccessHandler + attribute authentication-success-handler-ref {xsd:token}? +saml2-login.attlist &= + ## Reference to the AuthenticationFailureHandler + attribute authentication-failure-handler-ref {xsd:token}? +saml2-login.attlist &= + ## Reference to the AuthenticationManager + attribute authentication-manager-ref {xsd:token}? + +saml2-logout = + ## Configures SAML 2.0 Single Logout support + element saml2-logout {saml2-logout.attlist} +saml2-logout.attlist &= + ## The URL by which the relying or asserting party can trigger logout + attribute logout-url {xsd:token}? +saml2-logout.attlist &= + ## The URL by which the asserting party can send a SAML 2.0 Logout Request + attribute logout-request-url {xsd:token}? +saml2-logout.attlist &= + ## The URL by which the asserting party can send a SAML 2.0 Logout Response + attribute logout-response-url {xsd:token}? +saml2-logout.attlist &= + ## Reference to the RelyingPartyRegistrationRepository + attribute relying-party-registration-repository-ref {xsd:token}? +saml2-logout.attlist &= + ## Reference to the Saml2LogoutRequestValidator + attribute logout-request-validator-ref {xsd:token}? +saml2-logout.attlist &= + ## Reference to the Saml2LogoutRequestResolver + attribute logout-request-resolver-ref {xsd:token}? +saml2-logout.attlist &= + ## Reference to the Saml2LogoutRequestRepository + attribute logout-request-repository-ref {xsd:token}? +saml2-logout.attlist &= + ## Reference to the Saml2LogoutResponseValidator + attribute logout-response-validator-ref {xsd:token}? +saml2-logout.attlist &= + ## Reference to the Saml2LogoutResponseResolver + attribute logout-response-resolver-ref {xsd:token}? + +relying-party-registrations = + ## Container element for relying party(ies) registered with a SAML 2.0 identity provider + element relying-party-registrations {relying-party-registrations.attlist, relying-party-registration+, asserting-party*} +relying-party-registrations.attlist &= + ## The identifier by which to refer to the repository in other beans + attribute id {xsd:token}? + +relying-party-registration = + ## Represents a relying party registered with a SAML 2.0 identity provider + element relying-party-registration {relying-party-registration.attlist, signing-credential*, decryption-credential*} +relying-party-registration.attlist &= + ## The ID that uniquely identifies the relying party registration. + attribute registration-id {xsd:token} +relying-party-registration.attlist &= + ## The location of the Identity Provider's metadata. + attribute metadata-location {xsd:token}? +relying-party-registration.attlist &= + ## The relying party's EntityID + attribute entity-id {xsd:token}? +relying-party-registration.attlist &= + ## The Assertion Consumer Service Location + attribute assertion-consumer-service-location {xsd:token}? +relying-party-registration.attlist &= + ## The Assertion Consumer Service Binding + attribute assertion-consumer-service-binding {xsd:token}? +relying-party-registration.attlist &= + ## A reference to the associated asserting party. + attribute asserting-party-id {xsd:token}? +relying-party-registration.attlist &= + ## The relying party SingleLogoutService Location + attribute single-logout-service-location {xsd:token}? +relying-party-registration.attlist &= + ## The relying party SingleLogoutService Response Location + attribute single-logout-service-response-location {xsd:token}? +relying-party-registration.attlist &= + ## The relying party SingleLogoutService Binding + attribute single-logout-service-binding {xsd:token}? + +signing-credential = + ## The relying party's signing credential + element signing-credential {signing-credential.attlist} +signing-credential.attlist &= + ## The private key location + attribute private-key-location {xsd:token} +signing-credential.attlist &= + ## The certificate location + attribute certificate-location {xsd:token} + +decryption-credential = + ## The relying party's decryption credential + element decryption-credential {decryption-credential.attlist} +decryption-credential.attlist &= + ## The private key location + attribute private-key-location {xsd:token} +decryption-credential.attlist &= + ## The certificate location + attribute certificate-location {xsd:token} + +asserting-party = + ## The configuration metadata of the Asserting party + element asserting-party {asserting-party.attlist, verification-credential*, encryption-credential*} +asserting-party.attlist &= + ## A unique identifier of the asserting party. + attribute asserting-party-id {xsd:token} +asserting-party.attlist &= + ## The asserting party's EntityID. + attribute entity-id {xsd:token} +asserting-party.attlist &= + ## Indicates the asserting party's preference that relying parties should sign the AuthnRequest before sending + attribute want-authn-requests-signed {xsd:token}? +asserting-party.attlist &= + ## The SingleSignOnService Location. + attribute single-sign-on-service-location {xsd:token} +asserting-party.attlist &= + ## The SingleSignOnService Binding. + attribute single-sign-on-service-binding {xsd:token}? +asserting-party.attlist &= + ## A comma separated list of org.opensaml.saml.ext.saml2alg.SigningMethod Algorithms for this asserting party, in preference order. + attribute signing-algorithms {xsd:token}? +asserting-party.attlist &= + ## The asserting party SingleLogoutService Location + attribute single-logout-service-location {xsd:token}? +asserting-party.attlist &= + ## The asserting party SingleLogoutService Response Location + attribute single-logout-service-response-location {xsd:token}? +asserting-party.attlist &= + ## The asserting party SingleLogoutService Binding + attribute single-logout-service-binding {xsd:token}? + +verification-credential = + ## The relying party's verification credential + element verification-credential {verification-credential.attlist} +verification-credential.attlist &= + ## The private key location + attribute private-key-location {xsd:token} +verification-credential.attlist &= + ## The certificate location + attribute certificate-location {xsd:token} + +encryption-credential = + ## The asserting party's encryption credential + element encryption-credential {encryption-credential.attlist} +encryption-credential.attlist &= + ## The private key location + attribute private-key-location {xsd:token} +encryption-credential.attlist &= + ## The certificate location + attribute certificate-location {xsd:token} + + +filter-chain-map = + ## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap + element filter-chain-map {filter-chain-map.attlist, filter-chain+} +filter-chain-map.attlist &= + request-matcher? + +filter-chain = + ## Used within to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are assembled in a list in order to configure a FilterChainProxy, the most specific patterns must be placed at the top of the list, with most general ones at the bottom. + element filter-chain {filter-chain.attlist, empty} +filter-chain.attlist &= + (pattern | request-matcher-ref) +filter-chain.attlist &= + ## A comma separated list of bean names that implement Filter that should be processed for this FilterChain. If the value is none, then no Filters will be used for this FilterChain. + attribute filters {xsd:token} + +pattern = + ## The request URL pattern which will be mapped to the FilterChain. + attribute pattern {xsd:token} +request-matcher-ref = + ## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + attribute request-matcher-ref {xsd:token} + +filter-security-metadata-source = + ## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error. + element filter-security-metadata-source {fsmds.attlist, intercept-url+} +fsmds.attlist &= + use-expressions? +fsmds.attlist &= + id? +fsmds.attlist &= + request-matcher? + +http-basic = + ## Adds support for basic authentication + element http-basic {http-basic.attlist, empty} + +http-basic.attlist &= + ## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter. + attribute entry-point-ref {xsd:token}? +http-basic.attlist &= + ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter + attribute authentication-details-source-ref {xsd:token}? + +password-management = + ## Adds support for the password management. + element password-management {password-management.attlist, empty} + +password-management.attlist &= + ## The change password page. Defaults to "/change-password". + attribute change-password-page {xsd:string}? + +session-management = + ## Session-management related functionality is implemented by the addition of a SessionManagementFilter to the filter stack. + element session-management {session-management.attlist, concurrency-control?} + +session-management.attlist &= + ## Specifies that SessionAuthenticationStrategy must be explicitly invoked. Default false (i.e. SessionManagementFilter will implicitly invoke SessionAuthenticationStrategy). + attribute authentication-strategy-explicit-invocation {xsd:boolean}? +session-management.attlist &= + ## Indicates how session fixation protection will be applied when a user authenticates. If set to "none", no protection will be applied. "newSession" will create a new empty session, with only Spring Security-related attributes migrated. "migrateSession" will create a new session and copy all session attributes to the new session. In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. Throws an exception if "changeSessionId" is used in older containers. + attribute session-fixation-protection {"none" | "newSession" | "migrateSession" | "changeSessionId" }? +session-management.attlist &= + ## The URL to which a user will be redirected if they submit an invalid session indentifier. Typically used to detect session timeouts. + attribute invalid-session-url {xsd:token}? +session-management.attlist &= + ## Allows injection of the InvalidSessionStrategy instance used by the SessionManagementFilter + attribute invalid-session-strategy-ref {xsd:token}? +session-management.attlist &= + ## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter + attribute session-authentication-strategy-ref {xsd:token}? +session-management.attlist &= + ## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence. + attribute session-authentication-error-url {xsd:token}? + + +concurrency-control = + ## Enables concurrent session control, limiting the number of authenticated sessions a user may have at the same time. + element concurrency-control {concurrency-control.attlist, empty} + +concurrency-control.attlist &= + ## The maximum number of sessions a single authenticated user can have open at the same time. Defaults to "1". A negative value denotes unlimited sessions. + attribute max-sessions {xsd:token}? +concurrency-control.attlist &= + ## Allows injection of the SessionLimit instance used by the ConcurrentSessionControlAuthenticationStrategy + attribute max-sessions-ref {xsd:token}? +concurrency-control.attlist &= + ## The URL a user will be redirected to if they attempt to use a session which has been "expired" because they have logged in again. + attribute expired-url {xsd:token}? +concurrency-control.attlist &= + ## Allows injection of the SessionInformationExpiredStrategy instance used by the ConcurrentSessionFilter + attribute expired-session-strategy-ref {xsd:token}? +concurrency-control.attlist &= + ## Specifies that an unauthorized error should be reported when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session. If the session-authentication-error-url attribute is set on the session-management URL, the user will be redirected to this URL. + attribute error-if-maximum-exceeded {xsd:boolean}? +concurrency-control.attlist &= + ## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration. + attribute session-registry-alias {xsd:token}? +concurrency-control.attlist &= + ## Allows you to define an external SessionRegistry bean to be used by the concurrency control setup. + attribute session-registry-ref {xsd:token}? + + +remember-me = + ## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach. + element remember-me {remember-me.attlist} +remember-me.attlist &= + ## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application. If unset, it will default to a random value generated by SecureRandom. + attribute key {xsd:token}? + +remember-me.attlist &= + (token-repository-ref | remember-me-data-source-ref | remember-me-services-ref) + +remember-me.attlist &= + user-service-ref? + +remember-me.attlist &= + ## Exports the internally defined RememberMeServices as a bean alias, allowing it to be used by other beans in the application context. + attribute services-alias {xsd:token}? + +remember-me.attlist &= + ## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS (recommended). By default, secure cookies will be used if the request is made on a secure connection. + attribute use-secure-cookie {xsd:boolean}? + +remember-me.attlist &= + ## The period (in seconds) for which the remember-me cookie should be valid. + attribute token-validity-seconds {xsd:string}? + +remember-me.attlist &= + ## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful remember-me authentication. + attribute authentication-success-handler-ref {xsd:token}? +remember-me.attlist &= + ## The name of the request parameter which toggles remember-me authentication. Defaults to 'remember-me'. + attribute remember-me-parameter {xsd:token}? +remember-me.attlist &= + ## The name of cookie which store the token for remember-me authentication. Defaults to 'remember-me'. + attribute remember-me-cookie {xsd:token}? + +token-repository-ref = + ## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation. + attribute token-repository-ref {xsd:token} +remember-me-services-ref = + ## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider. It should also implement the LogoutHandler interface, which will be invoked when a user logs out. Typically the remember-me cookie would be removed on logout. + attribute services-ref {xsd:token}? +remember-me-data-source-ref = + ## DataSource bean for the database that contains the token repository schema. + data-source-ref + +anonymous = + ## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority. + element anonymous {anonymous.attlist} +anonymous.attlist &= + ## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to a random value generated by SecureRandom. + attribute key {xsd:token}? +anonymous.attlist &= + ## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser". + attribute username {xsd:token}? +anonymous.attlist &= + ## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS". + attribute granted-authority {xsd:token}? +anonymous.attlist &= + ## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property. + attribute enabled {xsd:boolean}? + + +port-mappings = + ## Defines the list of mappings between http and https ports for use in redirects + element port-mappings {port-mappings.attlist, port-mapping+} + +port-mappings.attlist &= empty + +port-mapping = + ## Provides a method to map http ports to https ports when forcing a redirect. + element port-mapping {http-port, https-port} + +http-port = + ## The http port to use. + attribute http {xsd:token} + +https-port = + ## The https port to use. + attribute https {xsd:token} + + +x509 = + ## Adds support for X.509 client authentication. + element x509 {x509.attlist} +x509.attlist &= + ## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),". + attribute subject-principal-regex {xsd:token}? +x509.attlist &= + ## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used. + user-service-ref? +x509.attlist &= + ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter + attribute authentication-details-source-ref {xsd:token}? + +jee = + ## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. + element jee {jee.attlist} +jee.attlist &= + ## A comma-separate list of roles to look for in the incoming HttpServletRequest. + attribute mappable-roles {xsd:token} +jee.attlist &= + ## Explicitly specifies which user-service should be used to load user data for container authenticated clients. If ommitted, the set of mappable-roles will be used to construct the authorities for the user. + user-service-ref? + +authentication-manager = + ## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans. + element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*} +authman.attlist &= + id? +authman.attlist &= + ## An alias you wish to use for the AuthenticationManager bean (not required it you are using a specific id) + attribute alias {xsd:token}? +authman.attlist &= + ## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. + attribute erase-credentials {xsd:boolean}? +authman.attlist &= + ## Use this ObservationRegistry to collect metrics on various parts of the filter chain + attribute observation-registry-ref {xsd:token}? + +authentication-provider = + ## Indicates that the contained user-service should be used as an authentication source. + element authentication-provider {ap.attlist & any-user-service & password-encoder?} +ap.attlist &= + ## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager. + ref? +ap.attlist &= + ## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data. + user-service-ref? + +user-service = + ## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required. + element user-service {id? & (properties-file | (user*))} +properties-file = + ## The location of a Properties file where each line is in the format of username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] + attribute properties {xsd:token}? + +user = + ## Represents a user in the application. + element user {user.attlist, empty} +user.attlist &= + ## The username assigned to the user. + attribute name {xsd:token} +user.attlist &= + ## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty. + attribute password {xsd:string}? +user.attlist &= + ## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR" + attribute authorities {xsd:token} +user.attlist &= + ## Can be set to "true" to mark an account as locked and unusable. + attribute locked {xsd:boolean}? +user.attlist &= + ## Can be set to "true" to mark an account as disabled and unusable. + attribute disabled {xsd:boolean}? + +jdbc-user-service = + ## Causes creation of a JDBC-based UserDetailsService. + element jdbc-user-service {id? & jdbc-user-service.attlist} +jdbc-user-service.attlist &= + ## The bean ID of the DataSource which provides the required tables. + attribute data-source-ref {xsd:token} +jdbc-user-service.attlist &= + cache-ref? +jdbc-user-service.attlist &= + ## An SQL statement to query a username, password, and enabled status given a username. Default is "select username,password,enabled from users where username = ?" + attribute users-by-username-query {xsd:token}? +jdbc-user-service.attlist &= + ## An SQL statement to query for a user's granted authorities given a username. The default is "select username, authority from authorities where username = ?" + attribute authorities-by-username-query {xsd:token}? +jdbc-user-service.attlist &= + ## An SQL statement to query user's group authorities given a username. The default is "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id" + attribute group-authorities-by-username-query {xsd:token}? +jdbc-user-service.attlist &= + role-prefix? + +csrf = +## Element for configuration of the CsrfFilter for protection against CSRF. It also updates the default RequestCache to only replay "GET" requests. + element csrf {csrf-options.attlist} +csrf-options.attlist &= + ## Specifies if csrf protection should be disabled. Default false (i.e. CSRF protection is enabled). + attribute disabled {xsd:boolean}? +csrf-options.attlist &= + ## The RequestMatcher instance to be used to determine if CSRF should be applied. Default is any HTTP method except "GET", "TRACE", "HEAD", "OPTIONS" + attribute request-matcher-ref { xsd:token }? +csrf-options.attlist &= + ## The CsrfTokenRepository to use. The default is HttpSessionCsrfTokenRepository wrapped by LazyCsrfTokenRepository. + attribute token-repository-ref { xsd:token }? +csrf-options.attlist &= + ## The CsrfTokenRequestHandler to use. The default is CsrfTokenRequestAttributeHandler. + attribute request-handler-ref { xsd:token }? + +headers = +## Element for configuration of the HeaderWritersFilter. Enables easy setting for the X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers. +element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & referrer-policy? & feature-policy? & permissions-policy? & cross-origin-opener-policy? & cross-origin-embedder-policy? & cross-origin-resource-policy? & header*)} +headers-options.attlist &= + ## Specifies if the default headers should be disabled. Default false. + attribute defaults-disabled {xsd:token}? +headers-options.attlist &= + ## Specifies if headers should be disabled. Default false. + attribute disabled {xsd:token}? +hsts = + ## Adds support for HTTP Strict Transport Security (HSTS) + element hsts {hsts-options.attlist} +hsts-options.attlist &= + ## Specifies if HTTP Strict Transport Security (HSTS) should be disabled. Default false. + attribute disabled {xsd:boolean}? +hsts-options.attlist &= + ## Specifies if subdomains should be included. Default true. + attribute include-subdomains {xsd:boolean}? +hsts-options.attlist &= + ## Specifies the maximum amount of time the host should be considered a Known HSTS Host. Default one year. + attribute max-age-seconds {xsd:integer}? +hsts-options.attlist &= + ## The RequestMatcher instance to be used to determine if the header should be set. Default is if HttpServletRequest.isSecure() is true. + attribute request-matcher-ref { xsd:token }? +hsts-options.attlist &= + ## Specifies if preload should be included. Default false. + attribute preload {xsd:boolean}? + +cors = +## Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is specified a HandlerMappingIntrospector is used as the CorsConfigurationSource +element cors { cors-options.attlist } +cors-options.attlist &= + ref? +cors-options.attlist &= + ## Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to use + attribute configuration-source-ref {xsd:token}? + +hpkp = + ## Adds support for HTTP Public Key Pinning (HPKP). + element hpkp {hpkp.pins,hpkp.attlist} +hpkp.pins = + ## The list with pins + element pins {hpkp.pin+} +hpkp.pin = + ## A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute + element pin { + ## The cryptographic hash algorithm + attribute algorithm { xsd:string }?, + text + } +hpkp.attlist &= + ## Specifies if HTTP Public Key Pinning (HPKP) should be disabled. Default false. + attribute disabled {xsd:boolean}? +hpkp.attlist &= + ## Specifies if subdomains should be included. Default false. + attribute include-subdomains {xsd:boolean}? +hpkp.attlist &= + ## Sets the value for the max-age directive of the Public-Key-Pins header. Default 60 days. + attribute max-age-seconds {xsd:integer}? +hpkp.attlist &= + ## Specifies if the browser should only report pin validation failures. Default true. + attribute report-only {xsd:boolean}? +hpkp.attlist &= + ## Specifies the URI to which the browser should report pin validation failures. + attribute report-uri {xsd:string}? + +content-security-policy = + ## Adds support for Content Security Policy (CSP) + element content-security-policy {csp-options.attlist} +csp-options.attlist &= + ## The security policy directive(s) for the Content-Security-Policy header or if report-only is set to true, then the Content-Security-Policy-Report-Only header is used. + attribute policy-directives {xsd:token}? +csp-options.attlist &= + ## Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. Defaults to false. + attribute report-only {xsd:boolean}? + +referrer-policy = + ## Adds support for Referrer Policy + element referrer-policy {referrer-options.attlist} +referrer-options.attlist &= + ## The policies for the Referrer-Policy header. + attribute policy {"no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"}? + +feature-policy = + ## Adds support for Feature Policy + element feature-policy {feature-options.attlist} +feature-options.attlist &= + ## The security policy directive(s) for the Feature-Policy header. + attribute policy-directives {xsd:token}? + +permissions-policy = + ## Adds support for Permissions Policy + element permissions-policy {permissions-options.attlist} +permissions-options.attlist &= + ## The policies for the Permissions-Policy header. + attribute policy {xsd:token}? + +cache-control = + ## Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for every request + element cache-control {cache-control.attlist} +cache-control.attlist &= + ## Specifies if Cache Control should be disabled. Default false. + attribute disabled {xsd:boolean}? + +frame-options = + ## Enable basic clickjacking support for newer browsers (IE8+), will set the X-Frame-Options header. + element frame-options {frame-options.attlist,empty} +frame-options.attlist &= + ## If disabled, the X-Frame-Options header will not be included. Default false. + attribute disabled {xsd:boolean}? +frame-options.attlist &= + ## Specify the policy to use for the X-Frame-Options-Header. + attribute policy {"DENY","SAMEORIGIN","ALLOW-FROM"}? +frame-options.attlist &= + ## Specify the strategy to use when ALLOW-FROM is chosen. + attribute strategy {"static","whitelist","regexp"}? +frame-options.attlist &= + ## Specify a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen. + ref? +frame-options.attlist &= + ## Specify a value to use for the chosen strategy. + attribute value {xsd:string}? +frame-options.attlist &= + ## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'. + ## Deprecated ALLOW-FROM is an obsolete directive that no longer works in modern browsers. Instead use + ## Content-Security-Policy with the + ## frame-ancestors + ## directive. + attribute from-parameter {xsd:string}? + + +xss-protection = + ## Enable basic XSS browser protection, supported by newer browsers (IE8+), will set the X-XSS-Protection header. + element xss-protection {xss-protection.attlist,empty} +xss-protection.attlist &= + ## disable the X-XSS-Protection header. Default is 'false' meaning it is enabled. + attribute disabled {xsd:boolean}? +xss-protection.attlist &= + ## Specify the value for the X-Xss-Protection header. Defaults to "0". + attribute header-value {"0"|"1"|"1; mode=block"}? + +content-type-options = + ## Add a X-Content-Type-Options header to the resopnse. Value is always 'nosniff'. + element content-type-options {content-type-options.attlist, empty} +content-type-options.attlist &= + ## If disabled, the X-Content-Type-Options header will not be included. Default false. + attribute disabled {xsd:boolean}? + +cross-origin-opener-policy = + ## Adds support for Cross-Origin-Opener-Policy header + element cross-origin-opener-policy {cross-origin-opener-policy-options.attlist,empty} +cross-origin-opener-policy-options.attlist &= + ## The policies for the Cross-Origin-Opener-Policy header. + attribute policy {"unsafe-none","same-origin","same-origin-allow-popups"}? + +cross-origin-embedder-policy = + ## Adds support for Cross-Origin-Embedder-Policy header + element cross-origin-embedder-policy {cross-origin-embedder-policy-options.attlist,empty} +cross-origin-embedder-policy-options.attlist &= + ## The policies for the Cross-Origin-Embedder-Policy header. + attribute policy {"unsafe-none","require-corp"}? + +cross-origin-resource-policy = + ## Adds support for Cross-Origin-Resource-Policy header + element cross-origin-resource-policy {cross-origin-resource-policy-options.attlist,empty} +cross-origin-resource-policy-options.attlist &= + ## The policies for the Cross-Origin-Resource-Policy header. + attribute policy {"cross-origin","same-origin","same-site"}? + +header= + ## Add additional headers to the response. + element header {header.attlist} +header.attlist &= + ## The name of the header to add. + attribute name {xsd:token}? +header.attlist &= + ## The value for the header. + attribute value {xsd:token}? +header.attlist &= + ## Reference to a custom HeaderWriter implementation. + ref? + +any-user-service = user-service | jdbc-user-service | ldap-user-service + +custom-filter = + ## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. + element custom-filter {custom-filter.attlist} + +custom-filter.attlist &= + ref + +custom-filter.attlist &= + (after | before | position) + +after = + ## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. + attribute after {named-security-filter} +before = + ## The filter immediately before which the custom-filter should be placed in the chain + attribute before {named-security-filter} +position = + ## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter. + attribute position {named-security-filter} + +named-security-filter = "FIRST" | "DISABLE_ENCODE_URL_FILTER" | "FORCE_EAGER_SESSION_FILTER" | "CHANNEL_FILTER" | "HTTPS_REDIRECT_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "SAML2_LOGOUT_REQUEST_FILTER" | "SAML2_LOGOUT_RESPONSE_FILTER" | "CSRF_FILTER" | "SAML2_LOGOUT_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "SAML2_AUTHENTICATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "SAML2_AUTHENTICATION_FILTER" | "FORM_LOGIN_FILTER" | "DEFAULT_RESOURCES_FILTER" | "LOGIN_PAGE_FILTER" | "LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST" diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd new file mode 100644 index 0000000000..e254b8488e --- /dev/null +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -0,0 +1,3837 @@ + + + + + + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + + + + + + + + + + + + + Whether a string should be base64 encoded + + + + + + + + Defines the strategy use for matching incoming requests. Currently the options are 'mvc' + (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions + and 'ciRegex' for case-insensitive regular expressions. + + + + + + + + + + + + + + + + Specifies an IP port number. Used to configure an embedded LDAP server, for example. + + + + + + + + Specifies a URL. + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + + + Defines a reference to a cache for use with a UserDetailsService. + + + + + + + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + + + A reference to an AuthenticationManager bean + + + + + + + + A reference to a DataSource bean + + + + + + + Enables Spring Security debugging infrastructure. This will provide human-readable + (multi-line) debugging information to monitor requests coming into the security filters. + This may include sensitive information, such as request parameters or headers, and should + only be used in a development environment. + + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + + + + + + + + + + + + + A non-empty string prefix that will be added to role strings loaded from persistent + storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is + non-empty. + + + + + + + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements + rather than the traditional list of configuration attributes. Defaults to 'true'. If + enabled, each attribute should contain a single boolean expression. If the expression + evaluates to 'true', access will be granted. + + + + + + + Defines an LDAP server location or starts an embedded server. The url indicates the + location of a remote server. If no url is given, an embedded server will be started, + listening on the supplied port number. The port is optional and defaults to 33389. A + Spring LDAP ContextSource bean will be registered for the server with the id supplied. + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + Specifies a URL. + + + + + + Specifies an IP port number. Used to configure an embedded LDAP server, for example. + + + + + + Username (DN) of the "manager" user identity which will be used to authenticate to a + (non-embedded) LDAP server. If omitted, anonymous access will be used. + + + + + + The password for the manager DN. This is required if the manager-dn is specified. + + + + + + Explicitly specifies an ldif file resource to load into an embedded LDAP server. The + default is classpath*:*.ldiff + + + + + + Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org" + + + + + + Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and + 'unboundid'. By default, it will depends if the library is available in the classpath. + + + + + + + + + + + + + + The optional server to use. If omitted, and a default LDAP server is registered (using + <ldap-server> with no Id), that server will be used. + + + + + + + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN + of the user. + + + + + + + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + + + + + The LDAP filter used to search for users (optional). For example "(uid={0})". The + substituted parameter is the user's login name. + + + + + + + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + + + + + The LDAP attribute name which contains the role name which will be used within Spring + Security. Defaults to "cn". + + + + + + + + Allows the objectClass of the user entry to be specified. If set, the framework will + attempt to load standard attributes for the defined class into the returned UserDetails + object + + + + + + + + + + + + + + Allows explicit customization of the loaded user object by specifying a + UserDetailsContextMapper bean which will be called with the context information from the + user's directory entry + + + + + + + This element configures a LdapUserDetailsService which is a combination of a + FilterBasedLdapUserSearch and a DefaultLdapAuthoritiesPopulator. + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + The optional server to use. If omitted, and a default LDAP server is registered (using + <ldap-server> with no Id), that server will be used. + + + + + + The LDAP filter used to search for users (optional). For example "(uid={0})". The + substituted parameter is the user's login name. + + + + + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN + of the user. + + + + + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + + + The LDAP attribute name which contains the role name which will be used within Spring + Security. Defaults to "cn". + + + + + + Defines a reference to a cache for use with a UserDetailsService. + + + + + + A non-empty string prefix that will be added to role strings loaded from persistent + storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is + non-empty. + + + + + + Allows the objectClass of the user entry to be specified. If set, the framework will + attempt to load standard attributes for the defined class into the returned UserDetails + object + + + + + + + + + + + + Allows explicit customization of the loaded user object by specifying a + UserDetailsContextMapper bean which will be called with the context information from the + user's directory entry + + + + + + + + + The optional server to use. If omitted, and a default LDAP server is registered (using + <ldap-server> with no Id), that server will be used. + + + + + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + + + The LDAP filter used to search for users (optional). For example "(uid={0})". The + substituted parameter is the user's login name. + + + + + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN + of the user. + + + + + + The LDAP attribute name which contains the role name which will be used within Spring + Security. Defaults to "cn". + + + + + + A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key + "{0}" must be present and will be substituted with the username. + + + + + + A non-empty string prefix that will be added to role strings loaded from persistent + storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is + non-empty. + + + + + + Allows the objectClass of the user entry to be specified. If set, the framework will + attempt to load standard attributes for the defined class into the returned UserDetails + object + + + + + + + + + + + + Allows explicit customization of the loaded user object by specifying a + UserDetailsContextMapper bean which will be called with the context information from the + user's directory entry + + + + + + + + + The attribute in the directory which contains the user password. Defaults to + "userPassword". + + + + + + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + + + + + + + + + + + + Can be used inside a bean definition to add a security interceptor to the bean and set up + access configuration attributes for the bean's methods + + + + + + + Defines a protected method and the access control configuration attributes that apply to + it. We strongly advise you NOT to mix "protect" declarations with any services provided + "global-method-security". + + + + + + + + + + + + + + Optional AccessDecisionManager bean ID to be used by the created method security + interceptor. + + + + + + Use the AuthorizationManager API instead of AccessDecisionManager (defaults to true) + + + + + + Use this AuthorizationManager instead of the default (supercedes + use-authorization-manager) + + + + + + + + + A method name + + + + + + Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B". + + + + + + + Creates a MethodSecurityMetadataSource instance + + + + + + + Defines a protected method and the access control configuration attributes that apply to + it. We strongly advise you NOT to mix "protect" declarations with any services provided + "global-method-security". + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements + rather than the traditional list of configuration attributes. Defaults to 'true'. If + enabled, each attribute should contain a single boolean expression. If the expression + evaluates to 'true', access will be granted. + + + + + + + Provides method security for all beans registered in the Spring application context. + Specifically, beans will be scanned for matches with Spring Security annotations. Where + there is a match, the beans will automatically be proxied and security authorization + applied to the methods accordingly. Interceptors are invoked in the order specified in + AuthorizationInterceptorsOrder. Use can create your own interceptors using Spring AOP. + Also, annotation-based interception can be overridden by expressions listed in + <protect-pointcut> elements. + + + + + + + Defines the SecurityExpressionHandler instance which will be used if expression-based + access-control is enabled. A default implementation (with no ACL support) will be used if + not supplied. + + + + + + + + + Defines a protected pointcut and the access control configuration attributes that apply to + it. Every bean registered in the Spring application context that provides a method that + matches the pointcut will receive security authorization. + + + + + + + + + + + + + + Specifies whether the use of Spring Security's pre and post invocation annotations + (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this + application context. Defaults to "true". + + + + + + Specifies whether the use of Spring Security's @Secured annotations should be enabled for + this application context. Defaults to "false". + + + + + + Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). + This will require the javax.annotation.security classes on the classpath. Defaults to + "false". + + + + + + If true, class-based proxying will be used instead of interface-based proxying. + + + + + + If set to aspectj, then use AspectJ to intercept method invocation + + + + + + + + + + + Specifies the security context holder strategy to use, by default uses a ThreadLocal-based + strategy + + + + + + Use this ObservationRegistry to collect metrics on various parts of the filter chain + + + + + + + Provides method security for all beans registered in the Spring application context. + Specifically, beans will be scanned for matches with the ordered list of + "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a + match, the beans will automatically be proxied and security authorization applied to the + methods accordingly. If you use and enable all four sources of method security metadata + (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 + security annotations), the metadata sources will be queried in that order. In practical + terms, this enables you to use XML to override method security metadata expressed in + annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize + etc.), @Secured and finally JSR-250. + + + + + + + + Allows the default expression-based mechanism for handling Spring Security's pre and post + invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be + replace entirely. Only applies if these annotations are enabled. + + + + + + + Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and + post invocation metadata from the annotated methods. + + + + + + + + + Customizes the PreInvocationAuthorizationAdviceVoter with the ref as the + PreInvocationAuthorizationAdviceVoter for the <pre-post-annotation-handling> element. + + + + + + + + + Customizes the PostInvocationAdviceProvider with the ref as the + PostInvocationAuthorizationAdvice for the <pre-post-annotation-handling> element. + + + + + + + + + + + + Defines the SecurityExpressionHandler instance which will be used if expression-based + access-control is enabled. A default implementation (with no ACL support) will be used if + not supplied. + + + + + + + + + + Defines a protected pointcut and the access control configuration attributes that apply to + it. Every bean registered in the Spring application context that provides a method that + matches the pointcut will receive security authorization. + + + + + + + + + Allows addition of extra AfterInvocationProvider beans which should be called by the + MethodSecurityInterceptor created by global-method-security. + + + + + + + + + + + + + + Specifies whether the use of Spring Security's pre and post invocation annotations + (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this + application context. Defaults to "disabled". + + + + + + + + + + + + Specifies whether the use of Spring Security's @Secured annotations should be enabled for + this application context. Defaults to "disabled". + + + + + + + + + + + + Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). + This will require the javax.annotation.security classes on the classpath. Defaults to + "disabled". + + + + + + + + + + + + Optional AccessDecisionManager bean ID to override the default used for method security. + + + + + + Optional RunAsmanager implementation which will be used by the configured + MethodSecurityInterceptor + + + + + + Allows the advice "order" to be set for the method security interceptor. + + + + + + If true, class based proxying will be used instead of interface based proxying. + + + + + + Can be used to specify that AspectJ should be used instead of the default Spring AOP. If + set, secured classes must be woven with the AnnotationSecurityAspect from the + spring-security-aspects module. + + + + + + + + + + + An external MethodSecurityMetadataSource instance can be supplied which will take priority + over other sources (such as the default annotations). + + + + + + A reference to an AuthenticationManager bean + + + + + + + + + + + + + + + An AspectJ expression, including the 'execution' keyword. For example, 'execution(int + com.foo.TargetObject.countLength(String))' (without the quotes). + + + + + + Access configuration attributes list that applies to all methods matching the pointcut, + e.g. "ROLE_A,ROLE_B" + + + + + + + Allows securing a Message Broker. There are two modes. If no id is specified: ensures that + any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver + registered as a custom argument resolver; ensures that the + SecurityContextChannelInterceptor is automatically registered for the + clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the + clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that + can be manually registered with the clientInboundChannel. + + + + + + + + Defines the SecurityExpressionHandler instance which will be used if expression-based + access-control is enabled. A default implementation (with no ACL support) will be used if + not supplied. + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. If specified, + explicit configuration within clientInboundChannel is required. If not specified, ensures + that any SimpAnnotationMethodMessageHandler has the + AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures + that the SecurityContextChannelInterceptor is automatically registered for the + clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the + clientInboundChannel. + + + + + + Disables the requirement for CSRF token to be present in the Stomp headers (default + false). Changing the default is useful if it is necessary to allow other origins to make + SockJS connections. + + + + + + Use this AuthorizationManager instead of deriving one from <intercept-message> elements + + + + + + Use AuthorizationManager API instead of SecurityMetadatasource (defaults to true) + + + + + + Use this SecurityContextHolderStrategy (note only supported in conjunction with the + AuthorizationManager API) + + + + + + + Creates an authorization rule for a websocket message. + + + + + + + + + + The destination ant pattern which will be mapped to the access attribute. For example, /** + matches any message with a destination, /admin/** matches any message that has a + destination that starts with admin. + + + + + + The access configuration attributes that apply for the configured message. For example, + permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role + 'ROLE_ADMIN'. + + + + + + The type of message to match on. Valid values are defined in SimpMessageType (i.e. + CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, + DISCONNECT_ACK, OTHER). + + + + + + + + + + + + + + + + + + + + Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created + by the namespace. + + + + + + + + + Container element for HTTP security configuration. Multiple elements can now be defined, + each with a specific pattern to which the enclosed security configuration applies. A + pattern can also be configured to bypass Spring Security's filters completely by setting + the "security" attribute to "none". + + + + + + + Specifies the access attributes and/or filter list for a particular set of URLs. + + + + + + + + + Defines the access-denied strategy that should be used. An access denied page can be + defined or a reference to an AccessDeniedHandler instance. + + + + + + + + + Sets up a form login configuration for authentication with a username and password + + + + + + + + + + + + Configures authentication support for SAML 2.0 Login + + + + + + + + + Configures SAML 2.0 Single Logout support + + + + + + + + + Adds support for X.509 client authentication. + + + + + + + + + + Adds support for basic authentication + + + + + + + + + Incorporates a logout processing filter. Most web applications require a logout filter, + although you may not require one if you write a controller to provider similar logic. + + + + + + + + + + Session-management related functionality is implemented by the addition of a + SessionManagementFilter to the filter stack. + + + + + + + Enables concurrent session control, limiting the number of authenticated sessions a user + may have at the same time. + + + + + + + + + + + + + Sets up remember-me authentication. If used with the "key" attribute (or no attributes) + the cookie-only implementation will be used. Specifying "token-repository-ref" or + "remember-me-data-source-ref" will use the more secure, persisten token approach. + + + + + + + + + Adds support for automatically granting all anonymous web requests a particular principal + identity and a corresponding granted authority. + + + + + + + + + Defines the list of mappings between http and https ports for use in redirects + + + + + + + Provides a method to map http ports to https ports when forcing a redirect. + + + + + + + + + + + + + + + Defines the SecurityExpressionHandler instance which will be used if expression-based + access-control is enabled. A default implementation (with no ACL support) will be used if + not supplied. + + + + + + + + + + + + + + + + + The request URL pattern which will be mapped to the filter chain created by this <http> + element. If omitted, the filter chain will match all requests. + + + + + + When set to 'none', requests matching the pattern attribute will be ignored by Spring + Security. No security filters will be applied and no SecurityContext will be available. If + set, the <http> element must be empty, with no children. + + + + + + + + + + + Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + + + + + + Optional attribute specifying the ID of the RequestMatcher implementation used to decide + whether to redirect a request to HTTPS + + + + + + A legacy attribute which automatically registers a login form, BASIC authentication and a + logout URL and logout services. If unspecified, defaults to "false". We'd recommend you + avoid using this and instead explicitly configure the services you require. + + + + + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements + rather than the traditional list of configuration attributes. Defaults to 'true'. If + enabled, each attribute should contain a single boolean expression. If the expression + evaluates to 'true', access will be granted. + + + + + + A reference to a SecurityContextHolderStrategy bean. This can be used to customize how the + SecurityContextHolder is stored during a request + + + + + + Controls the eagerness with which an HTTP session is created by Spring Security classes. + If not set, defaults to "ifRequired". If "stateless" is used, this implies that the + application guarantees that it will not create a session. This differs from the use of + "never" which means that Spring Security will not create a session, but will make use of + one if the application does. + + + + + + + + + + + + + + A reference to a SecurityContextRepository bean. This can be used to customize how the + SecurityContext is stored between requests. + + + + + + Optional attribute that specifies that the SecurityContext should require explicit saving + rather than being synchronized from the SecurityContextHolder. Defaults to "true". + + + + + + Defines the strategy use for matching incoming requests. Currently the options are 'mvc' + (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions + and 'ciRegex' for case-insensitive regular expressions. + + + + + + + + + + + + + + Provides versions of HttpServletRequest security methods such as isUserInRole() and + getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to + "true". + + + + + + If available, runs the request as the Subject acquired from the JaasAuthenticationToken. + Defaults to "false". + + + + + + Use AuthorizationManager API instead of SecurityMetadataSource (defaults to true) + + + + + + Use this AuthorizationManager instead of deriving one from <intercept-url> elements + + + + + + Optional attribute specifying the ID of the AccessDecisionManager implementation which + should be used for authorizing HTTP requests. + + + + + + Optional attribute specifying the realm name that will be used for all authentication + features that require a realm name (eg BASIC and Digest authentication). If unspecified, + defaults to "Spring Security Application". + + + + + + Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter. + + + + + + Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults + to "false" + + + + + + Corresponds to the shouldFilterAllDispatcherTypes property of AuthorizationFilter. Do not + work when use-authorization-manager=false. Defaults to "true". + + + + + + Prevents the jsessionid parameter from being added to rendered URLs. Defaults to "true" + (rewriting is disabled). + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + A reference to an AuthenticationManager bean + + + + + + Use this ObservationRegistry to collect metrics on various parts of the filter chain + + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + The access denied page that an authenticated user will be redirected to if they request a + page which they don't have the authority to access. + + + + + + + + The access denied page that an authenticated user will be redirected to if they request a + page which they don't have the authority to access. + + + + + + + + + The request URL pattern which will be mapped to the FilterChain. + + + + + + Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + + + + + + The access configuration attributes that apply for the configured path. + + + + + + The HTTP Method for which the access configuration attributes should apply. If not + specified, the attributes will apply to any method. + + + + + + + + + + + + + + + + + + Used to specify that a URL must be accessed over http or https, or that there is no + preference. The value should be "http", "https" or "any", respectively. + + + + + + The path to the servlet. This attribute is only applicable when 'request-matcher' is + 'mvc'. In addition, the value is only required in the following 2 use cases: 1) There are + 2 or more HttpServlet's registered in the ServletContext that have mappings starting with + '/' and are different; 2) The pattern starts with the same value of a registered + HttpServlet path, excluding the default (root) HttpServlet '/'. + + + + + + + + + Specifies the URL that will cause a logout. Spring Security will initialize a filter that + responds to this particular URL. Defaults to /logout if unspecified. + + + + + + Specifies the URL to display once the user has logged out. If not specified, defaults to + <form-login-login-page>/?logout (i.e. /login?logout). + + + + + + Specifies whether a logout also causes HttpSession invalidation, which is generally + desirable. If unspecified, defaults to true. + + + + + + A reference to a LogoutSuccessHandler implementation which will be used to determine the + destination to which the user is taken after logging out. + + + + + + A comma-separated list of the names of cookies which should be deleted when the user logs + out + + + + + + + Allow the RequestCache used for saving requests during the login process to be set + + + + + + + + + + + The URL that the login form is posted to. If unspecified, it defaults to /login. + + + + + + The name of the request parameter which contains the username. Defaults to 'username'. + + + + + + The name of the request parameter which contains the password. Defaults to 'password'. + + + + + + The URL that will be redirected to after successful authentication, if the user's previous + action could not be resumed. This generally happens if the user visits a login page + without having first requested a secured operation that triggers authentication. If + unspecified, defaults to the root of the application. + + + + + + Whether the user should always be redirected to the default-target-url after login. + + + + + + The URL for the login page. If no login URL is specified, Spring Security will + automatically create a login URL at GET /login and a corresponding filter to render that + login URL when requested. + + + + + + The URL for the login failure page. If no login failure URL is specified, Spring Security + will automatically create a failure login URL at /login?error and a corresponding filter + to render that login failure URL when requested. + + + + + + Reference to an AuthenticationSuccessHandler bean which should be used to handle a + successful authentication request. Should not be used in combination with + default-target-url (or always-use-default-target-url) as the implementation should always + deal with navigation to the subsequent destination + + + + + + Reference to an AuthenticationFailureHandler bean which should be used to handle a failed + authentication request. Should not be used in combination with authentication-failure-url + as the implementation should always deal with navigation to the subsequent destination + + + + + + Reference to an AuthenticationDetailsSource which will be used by the authentication + filter + + + + + + The URL for the ForwardAuthenticationFailureHandler + + + + + + The URL for the ForwardAuthenticationSuccessHandler + + + + + + + Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. + + + + + + + + + + Reference to the ClientRegistrationRepository + + + + + + Reference to the OAuth2AuthorizedClientRepository + + + + + + Reference to the OAuth2AuthorizedClientService + + + + + + Reference to the AuthorizationRequestRepository + + + + + + Reference to the OAuth2AuthorizationRequestResolver + + + + + + Reference to the authorization RedirectStrategy + + + + + + Reference to the OAuth2AccessTokenResponseClient + + + + + + Reference to the GrantedAuthoritiesMapper + + + + + + Reference to the OAuth2UserService + + + + + + Reference to the OpenID Connect OAuth2UserService + + + + + + The URI where the filter processes authentication requests + + + + + + The URI to send users to login + + + + + + Reference to the AuthenticationSuccessHandler + + + + + + Reference to the AuthenticationFailureHandler + + + + + + Reference to the JwtDecoderFactory used by OidcAuthorizationCodeAuthenticationProvider + + + + + + + Configures OAuth 2.0 Client support. + + + + + + + + + + + + + Reference to the ClientRegistrationRepository + + + + + + Reference to the OAuth2AuthorizedClientRepository + + + + + + Reference to the OAuth2AuthorizedClientService + + + + + + + Configures OAuth 2.0 Authorization Code Grant. + + + + + + + + + + Reference to the AuthorizationRequestRepository + + + + + + Reference to the authorization RedirectStrategy + + + + + + Reference to the OAuth2AuthorizationRequestResolver + + + + + + Reference to the OAuth2AccessTokenResponseClient + + + + + + + Container element for client(s) registered with an OAuth 2.0 or OpenID Connect 1.0 + Provider. + + + + + + + + + + + + Represents a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + + + + + + + + The ID that uniquely identifies the client registration. + + + + + + The client identifier. + + + + + + The client secret. + + + + + + The method used to authenticate the client with the provider. The supported values are + client_secret_basic, client_secret_post and none (public clients). + + + + + + + + + + + + + + + The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The + supported values are authorization_code, client_credentials and password. + + + + + + + + + + + + + The client’s registered redirect URI that the Authorization Server redirects the + end-user’s user-agent to after the end-user has authenticated and authorized access to the + client. + + + + + + A comma-separated list of scope(s) requested by the client during the Authorization + Request flow, such as openid, email, or profile. + + + + + + A descriptive name used for the client. The name may be used in certain scenarios, such as + when displaying the name of the client in the auto-generated login page. + + + + + + A reference to the associated provider. May reference a 'provider' element or use one of + the common providers (google, github, facebook, okta). + + + + + + + The configuration information for an OAuth 2.0 or OpenID Connect 1.0 Provider. + + + + + + + + + + The ID that uniquely identifies the provider. + + + + + + The Authorization Endpoint URI for the Authorization Server. + + + + + + The Token Endpoint URI for the Authorization Server. + + + + + + The UserInfo Endpoint URI used to access the claims/attributes of the authenticated + end-user. + + + + + + The authentication method used when sending the access token to the UserInfo Endpoint. The + supported values are header, form and query. + + + + + + + + + + + + + The name of the attribute returned in the UserInfo Response that references the Name or + Identifier of the end-user. + + + + + + The URI used to retrieve the JSON Web Key (JWK) Set from the Authorization Server, which + contains the cryptographic key(s) used to verify the JSON Web Signature (JWS) of the ID + Token and optionally the UserInfo Response. + + + + + + The URI used to discover the configuration information for an OAuth 2.0 or OpenID Connect + 1.0 Provider. + + + + + + + Configures authentication support as an OAuth 2.0 Resource Server. + + + + + + + + + + + + + + Reference to an AuthenticationManagerResolver + + + + + + Reference to a BearerTokenResolver + + + + + + Reference to a AuthenticationEntryPoint + + + + + + + Configures JWT authentication + + + + + + + + + + The URI to use to collect the JWK Set for verifying JWTs + + + + + + Reference to a JwtDecoder + + + + + + Reference to a Converter<Jwt, AbstractAuthenticationToken> + + + + + + + Configuration Opaque Token authentication + + + + + + + + + + The URI to use to introspect opaque token attributes + + + + + + The Client ID to use to authenticate the introspection request + + + + + + The Client secret to use to authenticate the introspection request + + + + + + Reference to an OpaqueTokenIntrospector + + + + + + Reference to an OpaqueTokenAuthenticationConverter responsible for converting successful + introspection result into an Authentication. + + + + + + + + + Reference to the RelyingPartyRegistrationRepository + + + + + + Reference to the Saml2AuthenticationRequestRepository + + + + + + Reference to the Saml2AuthenticationRequestResolver + + + + + + Reference to the AuthenticationConverter + + + + + + The URI where the filter processes authentication requests + + + + + + The URI to send users to login + + + + + + Reference to the AuthenticationSuccessHandler + + + + + + Reference to the AuthenticationFailureHandler + + + + + + Reference to the AuthenticationManager + + + + + + + + + The URL by which the relying or asserting party can trigger logout + + + + + + The URL by which the asserting party can send a SAML 2.0 Logout Request + + + + + + The URL by which the asserting party can send a SAML 2.0 Logout Response + + + + + + Reference to the RelyingPartyRegistrationRepository + + + + + + Reference to the Saml2LogoutRequestValidator + + + + + + Reference to the Saml2LogoutRequestResolver + + + + + + Reference to the Saml2LogoutRequestRepository + + + + + + Reference to the Saml2LogoutResponseValidator + + + + + + Reference to the Saml2LogoutResponseResolver + + + + + + + Container element for relying party(ies) registered with a SAML 2.0 identity provider + + + + + + + + + + + + + + The identifier by which to refer to the repository in other beans + + + + + + + Represents a relying party registered with a SAML 2.0 identity provider + + + + + + + + + + + + + + The ID that uniquely identifies the relying party registration. + + + + + + The location of the Identity Provider's metadata. + + + + + + The relying party's EntityID + + + + + + The Assertion Consumer Service Location + + + + + + The Assertion Consumer Service Binding + + + + + + A reference to the associated asserting party. + + + + + + The relying party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Location</a> + + + + + + The relying party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Response Location</a> + + + + + + The relying party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Binding</a> + + + + + + + The relying party's signing credential + + + + + + + + + + The private key location + + + + + + The certificate location + + + + + + + The relying party's decryption credential + + + + + + + + + + The private key location + + + + + + The certificate location + + + + + + + The configuration metadata of the Asserting party + + + + + + + + + + + + + + A unique identifier of the asserting party. + + + + + + The asserting party's EntityID. + + + + + + Indicates the asserting party's preference that relying parties should sign the + AuthnRequest before sending + + + + + + The <a + href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a> + Location. + + + + + + The <a + href="https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.5%20Endpoint">SingleSignOnService</a> + Binding. + + + + + + A comma separated list of org.opensaml.saml.ext.saml2alg.SigningMethod Algorithms for this + asserting party, in preference order. + + + + + + The asserting party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Location</a> + + + + + + The asserting party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Response Location</a> + + + + + + The asserting party <a + href="https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf#page=7">SingleLogoutService + Binding</a> + + + + + + + The relying party's verification credential + + + + + + + + + + The private key location + + + + + + The certificate location + + + + + + + The asserting party's encryption credential + + + + + + + + + + The private key location + + + + + + The certificate location + + + + + + + Used to explicitly configure a FilterChainProxy instance with a FilterChainMap + + + + + + + + + + + + + Defines the strategy use for matching incoming requests. Currently the options are 'mvc' + (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions + and 'ciRegex' for case-insensitive regular expressions. + + + + + + + + + + + + + + + Used within to define a specific URL pattern and the list of filters which apply to the + URLs matching that pattern. When multiple filter-chain elements are assembled in a list in + order to configure a FilterChainProxy, the most specific patterns must be placed at the + top of the list, with most general ones at the bottom. + + + + + + + + + + The request URL pattern which will be mapped to the FilterChain. + + + + + + Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + + + + + + A comma separated list of bean names that implement Filter that should be processed for + this FilterChain. If the value is none, then no Filters will be used for this FilterChain. + + + + + + + + The request URL pattern which will be mapped to the FilterChain. + + + + + + + + Allows a RequestMatcher instance to be used, as an alternative to pattern-matching. + + + + + + + Used to explicitly configure a FilterSecurityMetadataSource bean for use with a + FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy + explicitly, rather than using the <http> element. The intercept-url elements used should + only contain pattern, method and access attributes. Any others will result in a + configuration error. + + + + + + + Specifies the access attributes and/or filter list for a particular set of URLs. + + + + + + + + + + + + + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements + rather than the traditional list of configuration attributes. Defaults to 'true'. If + enabled, each attribute should contain a single boolean expression. If the expression + evaluates to 'true', access will be granted. + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + Defines the strategy use for matching incoming requests. Currently the options are 'mvc' + (for Spring MVC matcher), 'ant' (for ant path patterns), 'regex' for regular expressions + and 'ciRegex' for case-insensitive regular expressions. + + + + + + + + + + + + + + + + + Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter. + + + + + + Reference to an AuthenticationDetailsSource which will be used by the authentication + filter + + + + + + + Adds support for the password management. + + + + + + + + + + The change password page. Defaults to "/change-password". + + + + + + + + + Specifies that SessionAuthenticationStrategy must be explicitly invoked. Default false + (i.e. SessionManagementFilter will implicitly invoke SessionAuthenticationStrategy). + + + + + + Indicates how session fixation protection will be applied when a user authenticates. If + set to "none", no protection will be applied. "newSession" will create a new empty + session, with only Spring Security-related attributes migrated. "migrateSession" will + create a new session and copy all session attributes to the new session. In Servlet 3.1 + (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing + session and use the container-supplied session fixation protection + (HttpServletRequest#changeSessionId()). Defaults to "changeSessionId" in Servlet 3.1 and + newer containers, "migrateSession" in older containers. Throws an exception if + "changeSessionId" is used in older containers. + + + + + + + + + + + + + + The URL to which a user will be redirected if they submit an invalid session indentifier. + Typically used to detect session timeouts. + + + + + + Allows injection of the InvalidSessionStrategy instance used by the + SessionManagementFilter + + + + + + Allows injection of the SessionAuthenticationStrategy instance used by the + SessionManagementFilter + + + + + + Defines the URL of the error page which should be shown when the + SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error + code will be returned to the client. Note that this attribute doesn't apply if the error + occurs during a form-based login, where the URL for authentication failure will take + precedence. + + + + + + + + + The maximum number of sessions a single authenticated user can have open at the same time. + Defaults to "1". A negative value denotes unlimited sessions. + + + + + + Allows injection of the SessionLimit instance used by the + ConcurrentSessionControlAuthenticationStrategy + + + + + + The URL a user will be redirected to if they attempt to use a session which has been + "expired" because they have logged in again. + + + + + + Allows injection of the SessionInformationExpiredStrategy instance used by the + ConcurrentSessionFilter + + + + + + Specifies that an unauthorized error should be reported when a user attempts to login when + they already have the maximum configured sessions open. The default behaviour is to expire + the original session. If the session-authentication-error-url attribute is set on the + session-management URL, the user will be redirected to this URL. + + + + + + Allows you to define an alias for the SessionRegistry bean in order to access it in your + own configuration. + + + + + + Allows you to define an external SessionRegistry bean to be used by the concurrency + control setup. + + + + + + + + + The "key" used to identify cookies from a specific token-based remember-me application. + You should set this to a unique value for your application. If unset, it will default to a + random value generated by SecureRandom. + + + + + + Reference to a PersistentTokenRepository bean for use with the persistent token + remember-me implementation. + + + + + + A reference to a DataSource bean + + + + + + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + Exports the internally defined RememberMeServices as a bean alias, allowing it to be used + by other beans in the application context. + + + + + + Determines whether the "secure" flag will be set on the remember-me cookie. If set to + true, the cookie will only be submitted over HTTPS (recommended). By default, secure + cookies will be used if the request is made on a secure connection. + + + + + + The period (in seconds) for which the remember-me cookie should be valid. + + + + + + Reference to an AuthenticationSuccessHandler bean which should be used to handle a + successful remember-me authentication. + + + + + + The name of the request parameter which toggles remember-me authentication. Defaults to + 'remember-me'. + + + + + + The name of cookie which store the token for remember-me authentication. Defaults to + 'remember-me'. + + + + + + + + Reference to a PersistentTokenRepository bean for use with the persistent token + remember-me implementation. + + + + + + + + Allows a custom implementation of RememberMeServices to be used. Note that this + implementation should return RememberMeAuthenticationToken instances with the same "key" + value as specified in the remember-me element. Alternatively it should register its own + AuthenticationProvider. It should also implement the LogoutHandler interface, which will + be invoked when a user logs out. Typically the remember-me cookie would be removed on + logout. + + + + + + + + + + + + The key shared between the provider and filter. This generally does not need to be set. If + unset, it will default to a random value generated by SecureRandom. + + + + + + The username that should be assigned to the anonymous request. This allows the principal + to be identified, which may be important for logging and auditing. if unset, defaults to + "anonymousUser". + + + + + + The granted authority that should be assigned to the anonymous request. Commonly this is + used to assign the anonymous request particular roles, which can subsequently be used in + authorization decisions. If unset, defaults to "ROLE_ANONYMOUS". + + + + + + With the default namespace setup, the anonymous "authentication" facility is automatically + enabled. You can disable it using this property. + + + + + + + + + + The http port to use. + + + + + + + + The https port to use. + + + + + + + + + The regular expression used to obtain the username from the certificate's subject. + Defaults to matching on the common name using the pattern "CN=(.*?),". + + + + + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + Reference to an AuthenticationDetailsSource which will be used by the authentication + filter + + + + + + + Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration + with container authentication. + + + + + + + + + + A comma-separate list of roles to look for in the incoming HttpServletRequest. + + + + + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + + Registers the AuthenticationManager instance and allows its list of + AuthenticationProviders to be defined. Also allows you to define an alias to allow you to + reference the AuthenticationManager in your own beans. + + + + + + + Indicates that the contained user-service should be used as an authentication source. + + + + + + + + element which defines a password encoding strategy. Used by an authentication provider to + convert submitted passwords to hashed versions, for example. + + + + + + + + + + + + + Sets up an ldap authentication provider + + + + + + + Specifies that an LDAP provider should use an LDAP compare operation of the user's + password to authenticate the user + + + + + + + element which defines a password encoding strategy. Used by an authentication provider to + convert submitted passwords to hashed versions, for example. + + + + + + + + + + + + + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + An alias you wish to use for the AuthenticationManager bean (not required it you are using + a specific id) + + + + + + If set to true, the AuthenticationManger will attempt to clear any credentials data in the + returned Authentication object, once the user has been authenticated. + + + + + + Use this ObservationRegistry to collect metrics on various parts of the filter chain + + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + + Creates an in-memory UserDetailsService from a properties file or a list of "user" child + elements. Usernames are converted to lower-case internally to allow for case-insensitive + lookups, so this should not be used if case-sensitivity is required. + + + + + + + Represents a user in the application. + + + + + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + + + + The location of a Properties file where each line is in the format of + username=password,grantedAuthority[,grantedAuthority][,enabled|disabled] + + + + + + + + + The username assigned to the user. + + + + + + The password assigned to the user. This may be hashed if the corresponding authentication + provider supports hashing (remember to set the "hash" attribute of the "user-service" + element). This attribute be omitted in the case where the data will not be used for + authentication, but only for accessing authorities. If omitted, the namespace will + generate a random value, preventing its accidental use for authentication. Cannot be + empty. + + + + + + One of more authorities granted to the user. Separate authorities with a comma (but no + space). For example, "ROLE_USER,ROLE_ADMINISTRATOR" + + + + + + Can be set to "true" to mark an account as locked and unusable. + + + + + + Can be set to "true" to mark an account as disabled and unusable. + + + + + + + Causes creation of a JDBC-based UserDetailsService. + + + + + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + + + + The bean ID of the DataSource which provides the required tables. + + + + + + Defines a reference to a cache for use with a UserDetailsService. + + + + + + An SQL statement to query a username, password, and enabled status given a username. + Default is "select username,password,enabled from users where username = ?" + + + + + + An SQL statement to query for a user's granted authorities given a username. The default + is "select username, authority from authorities where username = ?" + + + + + + An SQL statement to query user's group authorities given a username. The default is + "select g.id, g.group_name, ga.authority from groups g, group_members gm, + group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id" + + + + + + A non-empty string prefix that will be added to role strings loaded from persistent + storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is + non-empty. + + + + + + + Element for configuration of the CsrfFilter for protection against CSRF. It also updates + the default RequestCache to only replay "GET" requests. + + + + + + + + + + Specifies if csrf protection should be disabled. Default false (i.e. CSRF protection is + enabled). + + + + + + The RequestMatcher instance to be used to determine if CSRF should be applied. Default is + any HTTP method except "GET", "TRACE", "HEAD", "OPTIONS" + + + + + + The CsrfTokenRepository to use. The default is HttpSessionCsrfTokenRepository wrapped by + LazyCsrfTokenRepository. + + + + + + The CsrfTokenRequestHandler to use. The default is CsrfTokenRequestAttributeHandler. + + + + + + + Element for configuration of the HeaderWritersFilter. Enables easy setting for the + X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers. + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies if the default headers should be disabled. Default false. + + + + + + Specifies if headers should be disabled. Default false. + + + + + + + Adds support for HTTP Strict Transport Security (HSTS) + + + + + + + + + + Specifies if HTTP Strict Transport Security (HSTS) should be disabled. Default false. + + + + + + Specifies if subdomains should be included. Default true. + + + + + + Specifies the maximum amount of time the host should be considered a Known HSTS Host. + Default one year. + + + + + + The RequestMatcher instance to be used to determine if the header should be set. Default + is if HttpServletRequest.isSecure() is true. + + + + + + Specifies if preload should be included. Default false. + + + + + + + Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is + specified a HandlerMappingIntrospector is used as the CorsConfigurationSource + + + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to + use + + + + + + + Adds support for HTTP Public Key Pinning (HPKP). + + + + + + + + + + + + + + + + + + The list with pins + + + + + + + + + + + A pin is specified using the base64-encoded SPKI fingerprint as value and the + cryptographic hash algorithm as attribute + + + + + + The cryptographic hash algorithm + + + + + + + + + Specifies if HTTP Public Key Pinning (HPKP) should be disabled. Default false. + + + + + + Specifies if subdomains should be included. Default false. + + + + + + Sets the value for the max-age directive of the Public-Key-Pins header. Default 60 days. + + + + + + Specifies if the browser should only report pin validation failures. Default true. + + + + + + Specifies the URI to which the browser should report pin validation failures. + + + + + + + Adds support for Content Security Policy (CSP) + + + + + + + + + + The security policy directive(s) for the Content-Security-Policy header or if report-only + is set to true, then the Content-Security-Policy-Report-Only header is used. + + + + + + Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy + violations only. Defaults to false. + + + + + + + Adds support for Referrer Policy + + + + + + + + + + The policies for the Referrer-Policy header. + + + + + + + + + + + + + + + + + + + Adds support for Feature Policy + + + + + + + + + + The security policy directive(s) for the Feature-Policy header. + + + + + + + Adds support for Permissions Policy + + + + + + + + + + The policies for the Permissions-Policy header. + + + + + + + Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for + every request + + + + + + + + + + Specifies if Cache Control should be disabled. Default false. + + + + + + + Enable basic clickjacking support for newer browsers (IE8+), will set the X-Frame-Options + header. + + + + + + + + + + If disabled, the X-Frame-Options header will not be included. Default false. + + + + + + Specify the policy to use for the X-Frame-Options-Header. + + + + + + + + + + + + + Specify the strategy to use when ALLOW-FROM is chosen. + + + + + + + + + + + + + Defines a reference to a Spring bean Id. + + + + + + Specify a value to use for the chosen strategy. + + + + + + Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' + based strategy. Default is 'from'. Deprecated ALLOW-FROM is an obsolete directive that no + longer works in modern browsers. Instead use Content-Security-Policy with the <a + href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors">frame-ancestors</a> + directive. + + + + + + + Enable basic XSS browser protection, supported by newer browsers (IE8+), will set the + X-XSS-Protection header. + + + + + + + + + + disable the X-XSS-Protection header. Default is 'false' meaning it is enabled. + + + + + + Specify the value for the X-Xss-Protection header. Defaults to "0". + + + + + + + + + + + + + + Add a X-Content-Type-Options header to the resopnse. Value is always 'nosniff'. + + + + + + + + + + If disabled, the X-Content-Type-Options header will not be included. Default false. + + + + + + + Adds support for Cross-Origin-Opener-Policy header + + + + + + + + + + The policies for the Cross-Origin-Opener-Policy header. + + + + + + + + + + + + + + Adds support for Cross-Origin-Embedder-Policy header + + + + + + + + + + The policies for the Cross-Origin-Embedder-Policy header. + + + + + + + + + + + + + Adds support for Cross-Origin-Resource-Policy header + + + + + + + + + + The policies for the Cross-Origin-Resource-Policy header. + + + + + + + + + + + + + + Add additional headers to the response. + + + + + + + + + + The name of the header to add. + + + + + + The value for the header. + + + + + + Defines a reference to a Spring bean Id. + + + + + + + + Used to indicate that a filter bean declaration should be incorporated into the security + filter chain. + + + + + + + + + + + The filter immediately after which the custom-filter should be placed in the chain. This + feature will only be needed by advanced users who wish to mix their own filters into the + security filter chain and have some knowledge of the standard Spring Security filters. The + filter names map to specific Spring Security implementation filters. + + + + + + The filter immediately before which the custom-filter should be placed in the chain + + + + + + The explicit position at which the custom-filter should be placed in the chain. Use if you + are replacing a standard filter. + + + + + + + + The filter immediately after which the custom-filter should be placed in the chain. This + feature will only be needed by advanced users who wish to mix their own filters into the + security filter chain and have some knowledge of the standard Spring Security filters. The + filter names map to specific Spring Security implementation filters. + + + + + + + + The filter immediately before which the custom-filter should be placed in the chain + + + + + + + + The explicit position at which the custom-filter should be placed in the chain. Use if you + are replacing a standard filter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index 9d439ff0ab..2ee3810cd2 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -260,6 +260,12 @@ class SpringSecurityCoreVersionSerializableTests { String version = System.getProperty("springSecurityVersion"); String[] parts = version.split("\\."); parts[1] = String.valueOf(Integer.parseInt(parts[1]) - 1); + // FIXME: the 7 should not be hardcoded + if ("7".equals(parts[0]) && "-1".equals(parts[1])) { + // if it is version 7.0.x, the previous version is 6.5.x + parts[0] = String.valueOf(Integer.parseInt(parts[0]) - 1); + parts[1] = "5"; // FIXME: this should not be hard coded + } parts[2] = "x"; return String.join(".", parts); } diff --git a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java index 102033dcd3..ccab6cb535 100644 --- a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java +++ b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java @@ -65,7 +65,7 @@ public class XsdDocumentedTests { String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd"; - String schemaDocumentLocation = "org/springframework/security/config/spring-security-6.5.xsd"; + String schemaDocumentLocation = "org/springframework/security/config/spring-security-7.0.xsd"; XmlSupport xml = new XmlSupport(); @@ -151,8 +151,8 @@ public class XsdDocumentedTests { .list((dir, name) -> name.endsWith(".xsd")); // @formatter:on assertThat(schemas.length) - .withFailMessage("the count is equal to 27, if not then schemaDocument needs updating") - .isEqualTo(27); + .withFailMessage("the count is equal to 28, if not then schemaDocument needs updating") + .isEqualTo(28); } /** diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.AccessDeniedException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.AccessDeniedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..77c4777bd73dcee52f0f4fa7698f65fbf1998190 GIT binary patch literal 16530 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 F{|8&MHMz7Xv!qflF*!N4xL7Y3%6HDs zOUq23^C9;|nf9jwCI&_y2DZeKlA_F{5(Xikti-ZJ{hY+Sbp2qUP+q!qML`JzYguAW GX(|8>RVfkx literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e1dd1cc40a26bcb8c63a5e986b39909382668748 GIT binary patch literal 11098 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 PKlZg(eh>T3nP}#}f%Lc6 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.intercept.RunAsUserToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.access.intercept.RunAsUserToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8394c9a73882da2af97a15c33d066ec75d9efa91 GIT binary patch literal 1379 zcmb7E&rj4q82#E^TnOQpMiLKr0^`Ay$Q3UOB9JsJUj zCK?ls(Lca=^>6UtNj>`?$k~erzv%+g)nti1H0|`8?|bjfd;NF>16siishWXK6cf#D zMcQ;Bc{bxqZVY*7LE<#Qj(t59jt&I-{xAq+=~ z##9(axHfP;+$DQtmJ`vOU2E*p$jpZ@DHUrnL3lMaJGL|;hDl*yqENlaiPl&=WZ^|D zA^ZUxfR`y)?vJ{sXHacuqex_WN96>*f4F)emg7+$N}Di3+&&s34f~Eb4Wme7vI{IV zjL$Ag&XETKMs$^!8p62lVoN*}^@?R2*wVn2>gl>@%b0C5(%>{?+Wa1yx&G3w?!-q@uxzN}Zs_+6kx2ilAL$tF{%d<4j^%D#>ZDCu+u; zZ$3*546Uz)OI!8Y(t2ib4>>iJU;fFAyXj>XujbnxW zwzEdiW*VRIOjqN4!2&whtwUs|-@tpnWnjQsT<@KQ&uZh41XUqLr!7<6i?EO-@OUqnUxx PM?%Wv@d;G}Wy|spgi6*U literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AccountExpiredException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AccountExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..ad4812a76de5d41666c0f4535669f1cfe91a67d0 GIT binary patch literal 16839 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 Dh5S$w literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AnonymousAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e8872447c4e4b79e806c9228b3fd7a09c546b6fa GIT binary patch literal 787 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AuthenticationServiceException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.AuthenticationServiceException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4a1ed3a3e64d0287fc776ce653e8a2acb031bbad GIT binary patch literal 16765 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 QaTB{hI9?O{?i{WCAE~V?>i_@% literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.BadCredentialsException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.BadCredentialsException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7e447f50ac0cd07ddc6ccea49fe7a6725ea3b1db GIT binary patch literal 16758 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 X95Lp|ye+=QP3!{TxG(74J?j4-vVbQ} literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.CredentialsExpiredException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.CredentialsExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..32623133d13c2049c084db3ac236a30c4635d3ee GIT binary patch literal 16843 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 Hsn-7hYZ_67 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.DisabledException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.DisabledException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d98805575991ad7214f2873ac3af498112fbc25d GIT binary patch literal 16833 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 MJ6cTd&dJvQ0GMJ<0RR91 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InsufficientAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c642f5868bddd2a0de35f10acb5d36440e8ce662 GIT binary patch literal 16770 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.InternalAuthenticationServiceException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5f7b7e17458313f5e2d5aca60b7c352516ab56fa GIT binary patch literal 16862 zcmeHNYm6Ml5$-*|4aV5`g>5i4iw!aC+1U7j4fr^pUz{J@oedapGTxoL8+&(WJ=1$W zI}twuQADBy6i9*~kVN4jBBBI>04XR$5so1F6C@%DW=YI0Uq9q49gcuFPo{10`8}UaU z4G%vcuYX%1-aIDavLCpmBs#<3(#dzO`P)T910AB!E9NKH*yo;Tx}lWf#$LkTnUYLr zB$-a&?@Z#~LaSYT%o%Y?Ri{2w>T8nVYOz?J`TW$KGuJ=(cg6i>F`(h=_n$7ib@7&^ zdVLnez;NK7bdFZtKm6vVRhv(~@w-W4a<7IBhF1G%MF%&NH3@v3{> zFm#3pZmtE_FQM@*_llXJbjrsE0;fz6SKgZdi3WPAZjG#fP|gdRjYdES-HPEll;Tn~ zttq`~XRjB^Eu)R_gm^$qMssna8AO59#eO+yIrELrA~SVEZz z&WtlpuH5kFuXKp%w~MKReo%AdZZWg!)!lu~+EF*?6|>7#Ck%Uir{V_t$gsi6^j>jE z#iao(z8mAZclw}LbuFlwHCGP%l|+wUX(nK1)wt)78-!%^jA*n`5Tfvw6qB4rLyDba zT4+CSx_-UYy2+k2D%ww;Q}s?m;R9rgB;d~WflCk@sif-Ej#iu^sh75Ial@L1Qps%M zP^<^HbEMb=2E97L)XSbvUut`ohTOUvIMNSFH7_iec1Az9yJYt0mttYIQ&XOimVrqNR$qOC=2q#END4!9qH~rddw{+^!G*z6hCjUaUDwmNU=!a>hpc6@I_~tJ*|tUk&(4f zOHUB^fl>b)`=^$~g0f$)csK=}>JDDy0QgNT@7z{ ztx+Yx>Mvs&8*DVM8i{Pe*JdfEDykMx$Da()Tzp+dCjxCpc1CV@GYIGq&_0TtryE9- z#ee9JJl+k*D#v3t61am^(p=;}+{#||s$FHZnb*^Vsa}1=KW>bY{J&UD-D`94YWY4Bb~^yvrP!;V)k zk{|LaY$-926wBft=^19-{Wdo@WEB~4({LzS4oh9ZP!q9Hw@=ZYrix=~N&bLd`4T>9 z!7$GE0hjhK`MHdGMMKj++=krEifDWEur?4sV8zGXpcpB7gnCGAT2@Y#{Kg8?lQ&ay zJYR0q`S0KXLyk^Y^!^MX`$hxVvvF@0|$G7 zUbD7RPR+v4!!}xFOz6H3&HZSO*Z@j{=>CEMpg7j}H4&exOe`y+tIo=c&kzK-*Dxb7Fuu0gOX1b?AsnwY0dSYW&;sC(3?K!^khz|! z;)dnGgHtL&ZAxYM+HMADw|c6W2&I&;!NzGcUqq8w!?&14 zG+##ZARPy-QE#$Wuf!vT0C z%Xr7=_#`>VG69_gYkXL+Uwsl|Pi0Jhhab>we#E1!Onjyz?0Sn%%CScE?uk2?g6jiB7Id{S6r(C^JKpf_Y3J&E8fxj z92&kx|L;I&I81mEn0|~V57X3pXf4;qYv~FC=M?gOMf2592^@+uRj%j~)2+pH>7bHo zpIf67oWf2}vNcI->i8ECSrrq}`p61w7wvUsSBhyGZw|V`yf)>(vACA8p~+i3DH20t zOX%DIP5Nt643=O+C2p&S&Nb_oGDQ9VJ0KWf|Ec1+VEYt;FeN zzj2B}Xb#8H$Uk8r{StI39Xk7D;4~;u>ux`sp`=YVz$5T7eDd}hoNQ+We%;w3Gfc}(v$1C(cI zw97F5Q#3zA(?W|FQi8_Uuh68)+1kMPuXBJ%0qA`j4f~K>K}}eiK=)1#Ig%rKe~aeq zudP=bsOMO0}%7@4I5xw9@23#5I$;SsN|3^f}&G#%7^5B zRArFEBy+N29(#$5zk&R(GiV>f*W+|oP`9+MYSkwH0|OVY@cfiA1o2Na?F$vqA77AW z_P(O-auAQQK74)K7Sv|+P~M0Orm2MaSm}#aS3F9qv>GyTwAoeI9~(3SJrlgfWvJ*n z*^>N$eB$qF;#MZfT>7g{vtAyiJUiYSlvEi`U1TZKxS!HEbYas`_Elqy<`d>~7Y?s5 z9nB2zkr0c?2(|*)!mP&_;<~fG{>OJbi20it@C7G5Ic()&`}x*o>Pnb&b7~TPCb(3G zixg{el$VsBzG(Mqp;Emi)sru$gN6f?#R`{YIOt@6{IpG)gQ$cRGqEr(Tt%Jve5}%B zZW?!?Mxu1Lif~GCd0sb@%IeKrjiG|eHQ{~Z66U&K!;!;XRd1-ym62h$eB5Hg@PJ(7 zjT3@5QW>(H$4X|7ngZA?EXL1-eJJf@ChK}&H0OB)ItdWBGO8eUw)l$0+F zOOo~(EkafE%0pBq74ExMqzh&;aNNt&$5S=XjNx>f}&TIbT-`K<_r9$Ay6L>Gd}$ zSzttDB>c&!$r*2>gT}S&Y9VI}HCW{w%JeTuJ;>>uFNZ ztlKJjD5Zrl+*O7GRJxt^l|G&+C$pC_aP&;Du9D_>@n+K+;>E%+3vB(yvBDf~8*2~` zDLDVE+04b((7N*q!w&h0naN^oX3z zdZ)myTbXP`ebx9tT1Atom}V|g5X~+Y&3?%30Gc}^q2f60p&o?0H)|2J!Sqf(nG|EJ zF)=^g6-lMgW7FEhw7|junuAhIM$VN$0jgn};}2@HqPodUSV!l0kS0g5B7Yw=|c7%1*dgCPc3 zZDCM}GbRxOBp#+s_~jZXnqwS1s5ffpz7fqjH0y01T=b-PNYpPmvBv=FDHz}r0GvWd z0c^2IWZsDZ!z~ej@|@^m{}8)W6e`ZmX-IO=kE}q3P3I1L*^id=+bDGJLxa7T0MM_R z(0wPGJ~W9(AF)O84d74)Abyi@H^%Nk^I5;SP%l$JnH4{XuS9(O1bSGTF@P5-3l>$* z0r;#}!BG)2>4TfGL>&X1uvc-7Sw#$xc+qjLo_v7L2%3{ZD*Ail0jM%Npq@nY6q{ zVt}V3b;BLLf-pgR9}TBoc{AJB45&O0%a3d{eTbSAcYKL4~r4*_I zV_`o>!wD-soopGAAgQ{G@z)H{3;0R_wN>6ZcR*CR1rxtO!-2!gIXqDn7QN?l{jM!5 zxF9FIAc3j8h=w=9|JTOPceTLt29R~ie}52pUH}Z`03=R;3w2F(8dr><;=-a46ghCJ zYXagz#SK>VNRF^3S|z?9O)@7A1kX;I(8su;q^e(%$O|24CPDbdx`AN>df-S3Q_xJ! z0K97eT9o40<1>a9028j&fst9ZGfP+J05IDIxOqG#jXNwL4U|(TYqOGu$qUdVYc-JM zD#L@R_7s-bOrl$f`U+s+WKrTid@kxmz>F+Y0j5zXM)ZllL@fq`EA7D}@Nxwtmefp> zUBXP2PQ{5)xE_reRJ9FsnOZ|(4gJgnxSx4J0z9>-6^v6zz)aXv0VU*QmEk@X(k9YPFnSA*%@Gurqs>9tqo literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.LockedException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.LockedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9cd1b8f9edd1c5472f8ce97ba007d2102e53e15d GIT binary patch literal 16831 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 i#*!-)B#F2@+6);#&b{>FmKTnH%D@w&*Yb literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.RememberMeAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6a1c85c45613b871c8e3815758e06a0cf6813f54 GIT binary patch literal 1200 zcmb7@zi$&U6vy9P0-@0K2M8pFGPQ^ST?A{Vw3If|K~d5OsYq1L-D~RR&OU61UO-f3 zVgm_;1VZo!AXfec1}0$UKcF)U1J9SzO8~X1htt`9e*S#l`})H!9McMFQnfvuC@$LT zip97kRmam9bQL!}k9Exk3c~|txD;L;V~ks z<_>tmA_J%WO?IDEA|~3E<<=$!W;Ru@coc+cOB=-k^B;h3?=NkO#c<4p!YY&p&@uGk zl$}cw#ZenL*9Yku9#!UL6cGvOoAsd-qG3GJ_h1{GG;ydx7cH}AL%lpyPd7y@L%z;g zD?*=Z^J{$O%Eup1CtPrRC`PnmU}E4J8)Ma8K0IB1&G|Xl`F!{1g)FHPSgJyr5Y(AG zOI0b>v)R+fU#DJwVs8uJ)S#&O156X@iL+I-Uph2*V4(x4Fl)H2QqODfIEipkF<~&Y z)y|glCR>$CMmXHnhOthXO%nqn^<{ryt=U+prZl z`cPIFOM}%gRH(Dgjgsv&{ZmhCp}l<60v+$i5!wD8IPcbo>*|4ASz)>w)t)!JCjI9G zrB#?@K_I)r+>~M=O}N5v6(;gEUj`k!bT*(J`G*(s8feI#ClaPL zJ<+}>np-SE&vs9wLxc3pD`X<|kJaB1L_Fb?e2; w-6wYn6lI-v{phut-nY-Zj1#7qkpuOkw0(zK4dv9p*h3*@^5~CL14XOyH(S7)F#rGn literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.TestingAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..daa0a4b41e2c6123fb4cbbd1c47deeb89956f501 GIT binary patch literal 534 zcmb7>Jx&8L5Jo49fFKkK3MgqPs5S?HCgLX`twcd2Bs%YU2u_@}@ywEhf}_wPAxaAF zLC+1i17o%zi4YR5Y|mJJ@0*uTSf&6cF7#9K!Ib^$phh@$VVDvYRWLkFRmC@0vMCfB zSEfBAmd4K9ZO;v{gnBg+NHSP20_yloSz_4C2I@|=tt$KN^L&5>?`NLbewihZwUZsfoy$j{MDuXIQD<@l1`O=@pU8Tg$d045f_!3+=PK Ab^rhX literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.UsernamePasswordAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c54f152cfccd18910f7b07d723e685d9f72d7c9c GIT binary patch literal 1118 zcmb7D&uddL9RK#UvlH2Lf{F+AGQoqqg4cQJX05`*j&((-prmvI3Mkj z=cFQt>{c3`T}Itn1gHII$~6(sU=Iod1ND<2s&=e1gt|kJ{Q7cZPuAn*0E%r`nqk6X zMCSJjIdX=`E{>64vPGcb>`XJ8Dp4JcFC|rIaZBh!|VZVo6fuGwY7MMMDE8P z|KdP9I5mFfX6_s;c$+L@y>%p3stgNLjKD;cEDkxUavN3%r7D%~fs(a>=Ge6j=kl{i z(VjoLFcXW}(lV2zBmTGN?2J84=2Nq%Ckf1m;oigY$(#@^;6gsv5BI7i6BY9v?uTK& z(UrG9-+UakykiD#9{(oy{qj1DemwqrHGo0{1?s04GuK!0F58CrDZf8#zI(s_`cZL` zi@PV+de!H`hjzH35={(o%H;ZE-1;TldgANHH=llhVc6t}7OZZFbS(SQ*@(O`QY#rH frrKh5wi;3GNvm1g8aP;fDV5T%riM5uc`yC}AAy9X literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8dbfc337f644eb9f0a4a7ab6fef20c973fd13344 GIT binary patch literal 11700 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 as1`7OocqAbJuePC_sl!6@0<(fg8u@Z4z;@g literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f0763d490fabce1b15462c2ad95b6e04ae44f95f GIT binary patch literal 11789 zcmeGiZH!$-b>6nL-9l-p{cfQY9<5NgyQQTcw52TD?RLv{x9)BW0z&TIH~aQ>?|b)h z@4W3U5h4~7#E3`?5=5fJfH7dy5UEjrm{=5%phS$(fMQ}uH2zWlXj1f?Gjr$8{dl`? zfq%F^X6MbEIp1^6nVI|C-`ROl$nNyRsucyHTd$6Vc8#C%!wD1v}HHMIIj!W zv4!i`Ej|f9tgh7HA=~vDA@2@(1tD!O>X`~$_|=2Jk3Igz?gxMCENNqGDr6(?f!Jsy zLfa9AM2W-_Wi)e-W9m1*A{;&(SdZ-QMrXRknKSVx-n?0VH20s+7Vn(9+`E$CgmyZZMHR~jjpB{dp3!NUk52_c#aO0bn) z6>Odz1Y(xGG)(bySVhrpa9M?Fn1>J{-FwjHBjApp(xU% zYIwrrW~bt2-+SWbu;f*+O@+LuX~ju9aFS=>v|?a$69zQzhinHNSg;kD5yFm0E;r@6 zjnHCqB{o+Hc2QN@jt}@1e!}(|rd8S=A$Y->vC$X1Mo+y8TMO98j3^yC8-==AZOU=AX%fIw7|OmkG-RJ(B^&pF2!|lNkWP)<|4KzAq%cKIQD@vMyQ% zPS(UMJz?mF+WZ%pKb0m{L4K~dSX$T~7CnP?0y2qEBwB-%VwEh*@@9gcRXknNgr}~+ z?W+YIC|32fYwS1Cyr4C50DCtIwm?!ffZBeqf!1Pg9V7+Vjueb|cOwiT52zSL!IMYv zV)kG7gNS#{$;w0$MnXR3L8%eP4_-M+Q5Et#ZRQ=YV1Zko^e41aLi}f2VR&01o`c-u zRS0MGY8sK0f749US}DDPwNqjlwK07z*tW~+w6@F82-Mql1NAjY=7~j+1O+=^b`o@` zr<<|q*Wq>ELQ*3{Z8X`*M%@)w;MoGxl;!xfnqQA(JvJm21m1ESvM0p(6`2v`RToGt zN!qc_G1dH0QQ9#BCCu6oIjsaW##a~-Y*lVd3pQ+!Vfz%B?FpHajlhL$VR4EK7N3GV zM&-X`vJcEE&jV1RWQUYg3j+-6ykb&{1LIH&loA@Wm$6Rt!|rk0t(PGVxfSx11W2%r z$&c&`E%$9EH`nA18Ot5ma1e^DuCUs`@~9gtRz(%l)cWEHCHZ>Fw8${#_Yn^J7vfyb zyo?Gd$kVsAqzy0!)ynm14_O222b6e%hvnGNlQ5#-Kv%X0apN*Q0vjv0QgOUel@tEh z3Ex%wxZG*#>Q1Gr8{aRlh^HdhQbo}v3DUG=co%HAC0em3YB^&s(F44acm|UH1U4y8 z__~sArX3)79Vqj9y@+#@ z1R&Uj4(|1?IvFp?At=ff#7F{+yF{#GDA=uYH1jYV^}&I;T{&zxIvQT4Ha~>p^`wgz9#+e+u}-7LXw6NXB;QeN zo|q$>ru&r-@-Z7us0XL(cFlE6UJ?64IobD7=?b;Z0YSgLFS@Lw&L& z?kX#^yJN@T77B_kq@Jn0*_;^I7P}-e@FFm)l$d-hNvPWKFhheW1yKv#C@D`vet!PpIyUN=L8#aY%Y(+z0ZCpRI z8e0OI_ouWP48=xL-Np#yHRG3bO621VHW~ev&H>_0IsJC2rDI+d&{9qbN zXuk;gKS_SNyLbsU%Bj!}pit{>zJfgl>|Bv!C)r`i_CtElL$KhJaGwR|reVCbr&px{ zPT2FrNwPJ5Sp@Xg6uXOJ%mturBf#fnIX-i4iA!k%{jdNDI3te!SOXO~8tgKh|2{S^ zV$;NmI3*R0y`N!|HMMCCoPW6h2n>LuuV6zlq)<_F)+VBRt$-Zp5l1PNy+1v*w2eME zpbxuQ@OTxX=~7ufF85%+#_2uIt+;>!ys-e+r|O2S8H_mqS@z>_QZRnbB+;iav{;oR z{KF;&LQG6Pf^%QQ=1~)Xh6y0y;Y%jKtUP4vWF+xr6T^&kF=WN_-huEVpAV@_(wP-8 zQIyEV8`S@mI8B^CfxWN5SwWuCx;)P$|1}MlNciE@GAiO9*tD)xg#Oq6wV6M!$g>=( zM|vOjo-`G;2S?!Eh(12ZT$s;vebMZQ2iGdirgR;h3P16KV9y+naXBjLoos#aL^1J~ zmGs6kG?9E_E-ksI)KRM%J7hUm;j_;3kil0`3bVOTaz@ zA>?bG-knE|!`t35^|XiABP5RgTA{3NRUyghNe*8$;Zqq(U!G;XGR;bQCySyqnpg!W zfP=Mk36p#Y-uxHiB}5dJJ3I9Q4FcT>QqqIT2P~zcIzJNdoUh&+klq2HM-KtB(;IHU zWr0?a)}LS-n#{zWP|^~%!2|TWK(Y7*dH~)6C)J}#{QN9mjW2FCrIf!=)=8b{G?`-+ zJ4$N54i!KNq_+rYD*~}TY>r@41O%_nI5mLHU?C7Hv<%|Wld@8%tG-~cDsBW@&KWnJ zcn_)}xXy>8DPHYEzK92vXp7=?rq$MvO!(ki+KeV3)B`@*H%_&l71M$ZxM= zqVW9Md{WypMeYtDM3v9%CvMRX{ZzSSu$m~{m+4E`Z{rTx5v+DA+@99-$LE;cDO4^ekwc73mZD% zp&vYuvBC`DDn|iLdNb@Rm7d{F<|y32!Iy${d1;PcyqOlSlCbEQCGvh9SdozfGfm=$ z6mN^x@!5WLxN&Y1}gPe+2+jIU@7 zmyM}!nH@-(Xg)lq>4Oxi<}j(|1nLc65=*znO2u?4-?#+3Ua6o3rh6$fNyf-xY-M&R z)=H`0q(w0YPkyD_vAILA`FQ6FAR*hBTw|$B1wkSz_tXMG*SYtcS^dJkXP1v}HHM7_ST0 zv4!i`Ej|f9tj^TnVcYc@AwT3s_K3$T-3a18vgzol$GTo=VQlK$NQ^`xv>j1Mib(AI z$^NUOpTE7ag_ZhPE1zXA$JU$T)XI-{)HU+iLfH6G;V(m7aKJ_@E62-d{vCR!7#r+KRDCHvQq~1o92V7({cPpT?`3ZG$O6zw)cMU>|2k%_~-wIk7X4Y{|EEvs+=8|)a5 zBD)H3D-F0IfxC9^9c(FhhBGk?8wMaQxg!Mu!`_5jr2ZaY8WZwY)+mI+J zx4>>a^W>IYZ+*IjExCy;8ui1PEqd8f&#m+RMs0+LeQdeo*-_Nz+Z7)6LwrJ>miMs> zD;y?J{w|zXqf16zj~h@+Yg~-^mDGq|X{2D5)oA1-4lglH-#!3KImumyGy2-Y*B zlMYer98wXp3tU#A8sedAd+xnx^I>pD&~f|Rfh|-USjDqzBNe+07KSKX-nAzPNZ2*N zA=`=Ewh4AUGU(O;rtY{t^aKyG+{vVe%N-vfdyNY86oV58-T?RdXm;U{gcVOpi-F@hJY85_N^YjoGEu(g1V%!m?lSxhBMf&EBxWMQveunS_? zMJeP2j?y~^3mWu3GPoUDmiy2H>9 zwfQeHe=1F^fvj9{v7oR$EN}+u1Y{DSNYsXuVwJ4O@@9gcQ9NDJgs0BH?X3kKC|32f zYwS1Cyr?yD5PLTYwn$PnfLea1f!1MfJtPI#jueb|S0fA|52zSL!IMYvV)kG7gNS#{ zcx569BOxF4pumXZ2d^BXs0#U=HuFwcu*j`X`V-nIA^x*%Fuc7G&mr#dDulCoHH}Eh zzj>xF~N> zF{u%vHkxd_QFnzEc(%YaWjTJW=GP-xg$+stfw!E1>XvQbL3FG8XcF*fnOm^)kdEw?dwh0137!`H@|r<-XnI z=9;`AW4Qwx4n2|88CDxu9(7^Gs;FX`+E6^9B;P=p78%C;KFneNLY&K)mr)@FdHVJ_ zX#>nbhnae{o2-HL14=x>!*XosNf=RZpex&hxN(^tfsK`0sW@J($_an;r0=SIT<$P+ zb(hlBjqjIN#8VM$xuWQj1Zi3_ybCroCt9&5YB^&s(F44acm|UHI5sIy__~sArX3)7 z9V*IG~aVefu8dB`1`uxc{;*$g=Te9#2wo(O_z6>EJ|e~8=u1F0c=t-JWecPL*hOR z>7Y64>rK>BJ%SlwW=?iQX`ryde@d7|b_gjcm0M-CKS#Dw=fzni{(Mg2m3b|if>Lmy z{U=p~>r*paao1V?>vU~X5A7>dlTFk8%7^%<4JXt?({;P%Iwr4({o$N$enmvFdAbFB*@hAA0V%=ZxI4Zma=t`^RsQ=yN?Su`RLN(4sLtt%O zKeHO=1hn8!X*C#%jikDb5y)%CFX@!X$7yUb`YoLW#G7;a?No0Pu|GobnjKO`T;lk_ zG}LZ>5%PbL{B(EmGHjGnp&dY>*42Ckdjieo??K`&)|LB{Aj#(3WA~^RgVDIk&{6w1IwDfCQWoM}Mq=iX07g z8P0zno0qU@Vnv*iipJh6*kp82GOdC0uNDA-0dVv+Y$%2lDr(-^M0BqgkOMv9D5bLZ zr>8k>qYn<~!)_KlUWI77RF;p+J=m{tdXIA}E}#H!EWq`tx?x)eV-7%;{WzQyjE|Tk zX01`PRXO5%)WkrDiOI)s?hDvFZUWFS0VF(p(FB;4hisjUB)()~n6WN~ta#o#5PszI zA(crwvmz#n61jMT`o9vViSsA1_Z2uR$WvOU=b7Zcrr{C^Kb%@dMf?++xhoZ+|NVb$ z=FcngEQjim-iN)XOhxU%5x6&^2h+@j`ApXr&5n3*ts5L%(M?>dqM4v(qOH-Gp8qWZ|Z90IqT1z^1C~OJ|rZCj2cT3{7b{ zHY@OFN-g?Euo=MK42I<0SsnkAGaiPaM|0q7PPt-CUjXt7e3}5KF8!{Ai*Cp)%5f=^ zi(nlE#!Kr@9klzDQsKQNGg7Rl6Pg2j7AvjKanMcx#n(1j4&o=Qgo(Au!&N+3%*R$m z=DJx0)f$DfRg6=xbw$HODsMM^G)5E9Yar~;{#gmryI^38u};se*6C$rj5`ws8=42a zYrJ+|@LDT%Gk9zvtw2+{6r0WXGv&q7IyiSRHkYITKsxpb$f@_BXw}e$uMjLdaFa(& z0r!QGC19U{5b`xo@6Mwq;BD`?dfLP55fVp#tx#6Cs*q&$B!@4W@Tm-?FVC`GnPxS; zlSNS)O{@YGz`xZ~ja15+aJq9Uc0C27&GZDe1xF1C~-zT^I>?&R6dZNbexf zqlbXm=?yjDvOudy>rb$aO=e-~swQpji9@-4Abplj_kVetwp(#uqo6Qp#T} z>!c2Jn#{3^9V4}0hYFws(o+Pq4S`rMHb=230)kg(oa)DBpb!WZS_bjxNm(h>RbMbz z6*qz{=ZqOoyzo694Z(Fj98K|RAM!;!s6<;5uQRRIMl#`pZ)ra^2h7RMz`<@~qvSd0 zk{>0~K9JvD#YExxwfUsBXNugNK#oFAQ-Q%%rlw;GofSKPJEwB|8}@7R$fUp8SXZ~4>r%tC5M$G?TT+;eZzj!k(UL|4CF-zqA zIR literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9977e555bbf9d12f284a3864512248c56a31d50c GIT binary patch literal 11774 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 A6951J literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9a132ba89879311a6173594945f785e90a316057 GIT binary patch literal 11704 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4fc6aa88bfb0a32e67258a9605f5a86c8a16c87a GIT binary patch literal 11707 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2f3e2c94c9505e99478048207510a3af8d9c664e GIT binary patch literal 11709 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.AuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..1524fa2be52ec91e6e9ae046842a9e872be2ad35 GIT binary patch literal 304 zcmZ4UmVvdnh`}enC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L-QL=g-wO-@cNE_MY;DVu)ZrN6>rH4_6vMG=E98Ac}+mlP!?m!Mh!Hv6Q) z^1qiFY=1(`*1=|Wa(-S(Y6Z}N1qC@!Cxf*nwY-k+a6kKyiGk6JfwLqtH?_DVF}DEd sMA59ovP8YolFS@EuuA`=tkmQZpI%NsiQL*1Agc-(7#OE53bCIL0B5OnWB>pF literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..945c17dd9916a57f8bbfdd367d8cc7a1453defa4 GIT binary patch literal 414 zcmZ4UmVvdnh#@?`C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L;*%qvMPN=z=vEK7Ankq<6SPEIW@b_J<=lBhIMBf`^}iGk6Ffjd1l52&Ri zHN~m2gh9|JE3qt5KPNFSUEet;vAEc}qKLtlbayx=6_b>qr@ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.event.LogoutSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..65880d2f3b495fc0996cc3e40895946b73bbd111 GIT binary patch literal 296 zcmZ4UmVvdnh`}YlC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj{U49L;*$xqKOEeS47PEIW@b_EH!eYP+zP|euR#K2Hd#NbQ1k&a2lB}IwJC5|Ze zfz3Xtu>9|(2HT$yvvshUot&Rnl3G!s=U7mX19d7`Yf{VW_zw5851AMky%;!4GILXl xOA>PnfKC+6N-Rs%D=o>)(F3dWPs&P7F7fH*^pnV~T>-MHfPsN=+M*EqbpSM~ak>Bi literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.JaasAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d433e15704abccae09ca0cc0f736571bbac3c74c GIT binary patch literal 1205 zcmb7D&1(}u6rXHUW06)XRPmr*DtM3$c-2cj7DGmfX{}6*^;uYVBH@@Se7v z&~eta0tO-N!ZWTwFbYDeuuZ88AK+9vw7;V}T#?ZTWI#yYlIlEV>yBH6y|<`y*grn8 zdJvH_%<|a7qS665AGPToElR3d#cH$78QhAxo-qkZIE;6UZh#aZ>?owk-b{riZieY)GW_x6@0Eb$B9ddidw%5lYFcH- za^L0mhpl(-4_-fBnB?N_{93R3T=>uqHg#gCrJytVW88Xqw8InMm|cAO0R~}BBu4Uz sr3(1yOOINl#v--6)pDvWW@oz^m7msYW>7BuGL(RbkCd_8hz~b7iTCrQ2+n{ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..638e87f4f382769600de8bcd527181f5fee8fd72 GIT binary patch literal 11326 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c18423dae2bf09764e5bde98413c2c59e2dca5c4 GIT binary patch literal 314 zcmZ4UmVvdnh#@q;C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3HLoNyIk6-& zKTj_!F|k-LwG1et=LKXsqR0l9CMTyB7rTO_<+;vr|42P&%EZ7>QN-X!H9NqD*NH{H z40-%44`R3uHp7$i^GZ@HO7t8H3UZ*12Ww4gc^%*3e)b^~1EUuMXGvymYH>+oZUNAZ rqFIS$iF&0anK^o3mHtUtsmUciy_|j$xwR`mRuwQXFiu+(Vt)+)9tC&y literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.DefaultOneTimeToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.DefaultOneTimeToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..806fbdee7f93bfb72806442ba61699283c3dff4d GIT binary patch literal 258 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2f775464d34d123590c04d3624deb825f7034a42 GIT binary patch literal 699 zcmb7CF;5#Y82#=N3MHaNfRIoH6I30liOo_EFXbu8X5{_GPMlf79{758tXAvZ${kLS7#HRMPQc4k&*t~lxe6RK=t0f=57|-) z-{mY47;-~TpBEPI9xldx@IojHdqObYH^yO{+wX7F^~TIB!|9)$e{%(?7dutuJhh@G zdn`4r*^y(<&;HI{{$^Jt@YbPh_%Y@w*wrq(Z|)vf?9;XX#@)u~Whb^U8cch&n~`G$ w@I_ICF^w%nSW6O(rijnA!`QtIc0F;!{X8Z3(8W>T9l=OuP)plQf}x@>&;9@O)c^nh literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authentication.password.CompromisedPasswordException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..edee78ff8baceb658e80513e755f380f05a4ced9 GIT binary patch literal 16772 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 F008nhjrITl literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDecision.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDecision.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3992b0122aacc8328aaffd7c7538c96b3352f4fe GIT binary patch literal 96 zcmZ4UmVvdnh`}MhC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflv9u&3zbLaRu_QA; oPtOsV=aQP7Sqv1tZ1pggBe9c#iGeYSfjzw_F|Q;wrJ{fl03x|0OaK4? literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.AuthorizationDeniedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6ab17b8908a50c4869612a85b4fa5e81a86ca1f8 GIT binary patch literal 11307 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 JsKJZR{{a$M4441_ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..54cb962030618297b3c956de083c3a5eafb80361 GIT binary patch literal 1581 zcmb7^O=uHA6vtoEv}q{zODl@hQ!5^17sZpk^urjGr7cYZ8o@HzOyjhho$c&wyREcV z5&QrZ6h)DG@Fe2Zt5*-=q4w;d7cbhg2NirXN!+BC7IO&fW9Gg8{Qtk1w_DKc3mD;| zWcZ$7ZfRPOGF{+e*6^tv2qqT|63DAuuq7fHcMUpEU1-XNz#UXA% zyV`?AX6sE7daW5UPs~6v$D9saTeUK?f#*4liUA8+1oZ<)N*J_Ii@8mUS<_-RXfYd9 zOy~{+p@0)R9mnRbq#-I-Gb^&R?!v8aQ+G0-HscVx04d4J)R&~}VVfQ$*-(-Vy>hHD zLv3l@PmLZbFTaihgdRZb=_~p3C3<*nr=d07MwSXjoT`Ue?C(&&?{Bf-(3%%t?a|X0 z*Vm4q91EJ~i4#x>-4*v7;+D*cihnPa=oY|OyO`BblX>VOw#@@qj&e60dJO5x zLuXX8xIL>%J$2mGFHKTc<@FB_9d$uvsYDQ3y(;2L`vLq`vK0FI8_B>Qo~J*`AxfM_m*o%m5@*karEG>F;%Zp^)auGtbCoNHuLc+ZJgOG Rx01Vn;N~G&s!)Wk{Q-H(GEM*h literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d2ec05e7e4de6d516e85c84b653300638580e9c2 GIT binary patch literal 1670 zcmbtVO-vI(82ws`r9q)cN;C#fU_6*@G@c|e{8$^w1_-5z)&w%$9qPb#XPKRaf&tN( zpeAaf(P#`8PsVul>eYksfSfVm;zc=o5EH-Iwrq<8V%$TMnST4e_r3RK_T3gVx&j8d zC}^%Dm|d6@q)6wunATisc!J4!jd=0~7i@t@#%+zxQd??$wR>qnY)Q?O`e(%qe@$E* z-v|Sg1PuHiu#b4>+V4ZR9(_W24qNn6w&*6Q0 z)_b63T`Fu$%?NQ_Opd9<3oIJr)6@q430uC0&4!?+Dj=3S1541PLri7QU=FeT4b&+8 zFAVzft`x+OdvsoZdwR)En=N5z$ia~s=G4@oS*l9WRr}b@H%tlc5C<9_dg!RebFNp?nsE&v{5yFunvX`+8pnP zIu8Z9Z_?T$*@xq~Tq zn6Zire%^wX(Hyi9!{DARhq#?8ISkX4gLtr~b7NXL}XsPJ?YfJ_{I8S%rL*QC{I1q2S^U2!dSIb#--qrhYe6uZhb4*Z*RU0ox zo<7@Jx!#~|1+3WrHt_A*tyR~KQ3Jf_5J4mtfqn>E&Vu65QIgPd)8^b+td1%nq5!dV o@4hxwj#A|-QE6FTU7`ka@hGid*eo`Y`+&jCL9|f*YM^R=0I>j7HUIzs literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasAssertionAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..92f6848e4d230927ed23f07c96f1321bf180c7db GIT binary patch literal 1454 zcma)6Ic(HG6#aYTgd8L&kb+d{Pna>6Hbi~z7$3|Fvi8;0vLhCi$lmX4S;UZTGdW;3O#B_(bd3{1T)npbU!>kwCrZA&Nw9IprdXbw+z@p{~iiqbE%-ON~EN0M<4ba zhnpk;Qf;xgVzz@N^;{=%3s{i~d_a{C&>1vZszpoX;H+EpEPLK&IfomzRKL3RAAR=i zc6S_N1|%IEQP5qtE!EKJhyD#0ZPR}auCHGHF%W{r%&V{r$-qZay%9=U2v#BVVCDV3 zd#~C31jMqCl=d}_2f(MCq<27zcjD6VZRIcX+{V;gb6d@q7UfH;#AN+i4ZZ!_g z2DCGU(aMz+8QoQ<_yy*p!##DuKq@0l@kV24gpy!-uHu0rraefV+RC(j<|sI|Mf@9) z_4GQA$@QfO+Yz2&On61whroLc=nMyEu`!+6XlUy|WNQ=xIXGJMRRxc8>BR0EbDzGv zjia5Eg3hR%a0&}6vGbQye}bmVtpKsR4`xnI1z5Q&svKvsfLKi}A78%eyYemp@iAz3 zJZ6nyn|UG&ZK{AC7Cgra{4-}mlY!8no4yGxwYgo5dT4*^LEe4+`KEpJ@aZGiwGG~_ z>E7!LFQ{Y$Lvh^vOn8xm;X&2HsVR7%Q6n=J`Iu681|AH!LPbmdac149M6(7J&oz!BXQ4$N)NR;vJG~Q&rGo2kL zYYK;;AyEvOZO0~ZA1!l4p3ggBt87Ya872TmNIXE=bwd$X~3owg}^u)MQx-hA(S z-}mOrJ1`n4m=kKnilp+xmGg>q_=ZqxR>a+|@^#O0S!A)UZu3z4F4MjUtyvaThgO!w z8V|ud`5+IYbtta!-f0%K9VoFV;)?cZIO^b0Hj`X&VPj(34SdXNud~4SOm4f{kFGfI zkgK>y=dvKuu*X?t>&y;VxMH7at#VgmNQq#(zGT4#xCnXN)5X(Ham{?%Q!xi_tIh7$ zX1hXhn>KjK2D_1NuEYxFcVuQ8E7ew{6?64HsQKxOCoYEbUO5jVO_<2+;~pZWcY$2{ z91%|^Rd%%>*s~%CuuP;5D=lteGQ8m2PGPz+Uj^ug)UV-B2z&0DYib;u;mxrAyomI!KZnx(1~>rwXj z(vJtPf6qQ1fm|I5k^csdC8{O2QJ`PkbaF?csZBUoMs5uH^=$wv4eds_F*0s-2U#38c5H^_Z*4slt8D>005VqzF8HH9c`({ReuUcHoi@vJ^DLZ3IrP;(!Cx_n|fMuK;zkuHeok&UC|Bo%Ob4B(#IR42~+8sBakRu+Ml^gvY|yD(ww|&4rl$c#ObOTlUtxo znfOkyGG*uR!Fmp-g32m2JCrfs=E3)GzxUB*g9JEnMCSwidH$x%hTm4cs6euBmeeyq2XVJC* literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d3e96900c7f1747ffbe780d473cc174af7e78880 GIT binary patch literal 552 zcmaKpu}%U(5QfJyXw;yIg_brJR>uQiL(rhfB^HpF*pR*50T-6rb9aElf=976F_sp- zhrMs$J2(r495HM)oB99b`~P|Wfr@v~wyq!h-07^}b7F*3>xQvMId+<6u@pWQV|v7l zv=pRm7B_`&qnl`n9W94QjncYfhnT_QMJ9qMfdlDK1-~$!;5ZqGiKrQo^=o(O043EE z*w+g|Popa<+7!6zg@e{c%r(SD>d6WDAKKU3#XM`N!w9w?pt|Bi#i-$LIk-kfJz1iT zNt;^J8pEudpK*5;lF-IK!5p@V9Js}^kSY$+_)qH3uSYq}67A{v^Yr8L_2oMPD00@{ zY>YF-biMU^Ov^=IEg4ExR~?QlVM8g0eu2mR?|GgX{8k0tsK^O+mO5J55mdsRIQCJO MkKXkp2n{>CziCXvjsO4v literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..a38371d3694f7c930f9730f0d58fff78b36c6f81 GIT binary patch literal 11073 zcmeHNYiu1y6&^dO*_&yE}9CJic@0%$b?{{eQCS;)wMJQNxPE$n_gzk=^7Mf@s2uxzmbVF>N`4Kjt

Sk;zVjIreleXpAe#08{Jl?Rq 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.authority.SimpleGrantedAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e127f24499a37c695213fbe6f5f70f08cde69bc3 GIT binary patch literal 125 zcmZ4UmVvdnh`}kpC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm}XFR`>FBOlBS z&de>yNp&wu%qvMvafAsofB{nu69c0U14~hUPHG8*kWW@(S)zVUVqUs_a0$qC>xzOB N26mT#zyQ~9R{$woDro=! literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.SecurityContextImpl.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.SecurityContextImpl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b3a0dd59fc98a4603a814b617355af144704130e GIT binary patch literal 153 zcmZ4UmVvdnh`~0$C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm|sNaU5IR+Q)k zLq(k-e9zp190o98%3)$)^kLvjEG@}M%`3@FPAtg;s$nql0UEB4X1G4gaD9;B`i>}i ItSbr%0Ite6y8r+H literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.TransientSecurityContext.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.context.TransientSecurityContext.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5a4ccd07b4d0d97d12c13023f0eb3ea4b04079f6 GIT binary patch literal 1294 zcmb7E&ubGw6n^E==zAkwgOa=;@v zYuzw__(=z8NO_QFJ$ncH37=Vkyu z)|oM=Mr#tVt~y*MEYlv$_?owfB@2v&bKVZS$J~I)wp-oW;l3?-FiraUB4oi`*n=rl zsd5@d zYjMj&UycPtdf+E7gi zr@i)nxTMXcW!V3G`{(5tH02YkTl1qP=-#j688K;F@UBRfyM7n8F9=Sx9_HT$>CB;_c5Je0lz6zd?TmIzNLai^<8l z<{YcOzgmCs^6<&63|5g=H%_nBJY9>}s1?->nPyh$L_dTbWPvyoBMbQlQmOFaXjBVX Gn(_}s!NceP literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.AbstractSessionEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.AbstractSessionEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..13d48179c5d1f76d4822c689d81a26882fc06d01 GIT binary patch literal 198 zcmZ4UmVvdnh`}zuC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflIlm|s$SW?+%+J$v zOe!uZN=z;ZhVWg>Qu9g{bozcjVqL(=#K2Hd#Gr%Cu;l!_lGKV4J;#EAoXq6J5};9F ztw}Af<2&5XK4fBG^kU#F$;?eHE=kNS02(8jl~|UjS6Y&pqX$;$pOlrFT;kKq=_ip} Ry8>iY0Rsc$v_&Bf+5o@|N#Xzi literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.session.ReactiveSessionInformation.serialized new file mode 100644 index 0000000000000000000000000000000000000000..384fdd554571827283d481622a98093aa67c8f58 GIT binary patch literal 867 zcmb7C&ubGw6n;q~v1qGR6h!nO^(Gq-ieOJ|jT#8HWE+Ht%5?T6PCGlZ&b+i6M9D$$ zC@2-df5DSSj~?~pAK;(Rvsd3FjT=wFz3jf-Z@%~a*w06B!aKNQT`%&PQ>NE-BE#!*~*gR+}&%wo8=>O>l0E(8Ba;n>)KGM}T7mjpScIOhNW)o|V|h zLZFTUbrhpJeEjeSaz@{rZM*N$B}hVPAGP_pFj?)u zl91B&4Lz`?KDOI|v&Flnm3x?U;DY2J(2x?^PeZF{#EuRbof3U|W;twyp5V;bexH=C z#TdMw%!Kz`O7a|D!5q&)mf@mCGh642{ahcp59gu{t2O7wwfN<>No}IKDlB8Z;gxqk z-+mglIgZ@HjoD`ku1o7M{PE=X)iRWtP?7`}r=%7zE`!x970lZX!{%Qfx85Hfy?Hbj z`e4M}|IdGU?Kr8yhD|f!1lg%hLd_MfD1@;-n|zY`Ac|F*X}st7U&Q3^ilS_`TX9xT i@+O#XZ8qyq+i|^>6D+ezw6n>Wmr4>?Xk&4s-rm~?6VnQklEupG7QIsPCK?1oxCw1bpUHcuq2!X=H zf`kM@LSkcP;D0b7v9hvtX5~3)xG+U{v7i05=SvNPEh5&G&)YF`@ZfOmoua*n5>$rLA?tNQCjIlmcV(%JhsJgAv_|iB?I=1 zH4Bugd559cPGBYU?Z4hMo`0G##Q&;A9Z7zW)gEzszzfj17kao{}~ zyo&BU!p$Xs(w-~>L~nll`uw#dJThdhBx~TpoHMBix|c2Uo+8MO;Uz3l9mdiW z%cL%CM2qxXt(5N?rN}c1!*6wTZZg@Ep&9XwFTeZ#_S3jiBSRcqTl}Zu+T4Nhw9u z!gY!$n6a~%eCGNnPGxSD*mF#y$o{sd!X~+OXVlDZgq8L|(t6rSTkR5I^|?02zLMHMz7Xv!qflIlm}Xue3O|C?&Nd nF*B!FFBHgDaV#y#$Op+g=jRqA7A2PC7cqbVQw|dYLq!1qM=u~7 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.User.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.User.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4602e2af21ae90873442ad4f88438894da86f137 GIT binary patch literal 299 zcmYk1F;2rk5JksE5CljhNL*trAvy|B2*?mCjYWaGVLdoYmR++uCZ?g|2yhB|5O?AZ z?2-be8vQ@|^WXb7ta}Fs)-}SnPMPM`;XN&_TL@3GbBdpYw2nmQ$<@TDv=>)lhu=wc z3WEwpD5dQT ?Tji*(VECsMRxYBnFM~sd6>9(gbU+4gG}Q%cW5;tFzAEwzyTu(o zV%D+JSxJ0Uz-Eiyhjul?-pbTynylnlJ^Hbx2?P)D3~ApcNdkdy6mvw(5jpyK$oiVR oyuN*Y9IgTM?Q$o;43AG%Og+QKcyf_no-%Az=jHf%R!z(N2j4|t#{d8T literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.core.userdetails.UsernameNotFoundException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5eb8b1c9b9e742a8114d1fee4a07053a851b2181 GIT binary patch literal 16762 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyControl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..51e783d58cf04c32fe63631115cce63f01a00412 GIT binary patch literal 96 zcmZ4UmVvdnh`~O;C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflCnd2!ub?15Co{QH uFCekF7$}_*0OmU9=am%Y=ct!j>38*Q=3!!BjAGzO2I|U8PRyw&U<3gFp(BI< literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cf7079ecb45727245afc3702b8eba9df05822c7b GIT binary patch literal 11328 zcmeGiTWlOx^{$gT51Qsd(!AQnX|@RvI!>B2Y3h)6Yp)Xr$9BC=(l({hc=mcd_Uz1L z=B{H$sA?${R7hwM4<>#kfKQR0}ujI74ZQ`AR#0kKUH~%FaD4UoO54u=dt#> z?O)lCtJ!TtQY2lN%hn6;npG3?r^yB-*PX`-aK7I%T%& zouP4THvn#v0as(F!@dh-EvUemorr7)Aa1*m0#O51k2a~#0OjVm6^0QYq;<_TsBeRq z)?%*LJM6}+Z$7+49w%!UIWRFzdvKEH(t1xQZPMe$J;79u>&LCBDc5lUdC#Sm?STWyV5mYPLQ(SZne(3n|w{Aa%S_%mvFM(g|OthJsV6VCU<-JG#_;eRp{Q&8n3ZkaX zhR9ma_322fIZ2~ovflB4v*Ez5(`W?T3YqU7CO6e744|U=aa{JUo^m~EK&@?3HXYPc zJwd&df?3z(J?Cf?gAZ~<^I?gQu5LzF*kQ=X$wfW8#$CQ99lbw@s69FIBolN4>W0=jcHVqzNJZw zMS%kj8bpljSsXy}unE?No;^Fvf?t7{*uVVdUn7ob1zr zoi@mjh7Lts`1OcnT0%VfKxRI5S^>$GlCQh{;2 z14;=EzLv2V45I#N+x5#3huk{%lmv*8UCE#93@!JACO3EH4XNY~ZKzdas}eO@SV#2- zP#H?9n5K3X4@k*(@=S{iV}75Yuzn%V<;+WX#RYl#k&d(h=HLaf->7nHVEup+&(f%@ z3_S-u5)O1_dk{Bn*FCVXax*2zTVy#AOq~l{xsJ=Jn&L63tNY(6uZZUYBkLtamrIbQ zCBi!+wT@^hPt_w#ReG@>oj&E7lV?8W)mjEuK_*4$gS;$q>F4%ErSHO zeAE<>Il)fl?A<~t=Xt3;I7*%~$dTdgOC zUoF^qh!vZ#YBKsv1|0uhF#)Pe0epo6Fw&R!m`<*XiHZd<@-$(`vrreCf2DXkrK+Wr zD<EXVDluTgZ8NJF;NTkFk*z6j)jB528EKs zblVZ6q*QJd)qaO;9W&WlQsU=w5^u_D(ZpEKOu)Y>9q!=(j6AeVGuL3N4-QQ2`YFTF z(eNU*!NCrV=3G1(u{wrTI*nVCO*gd@c~i1^ZkcSF?pGe5Q#R~S2Nrz0={hE_i2cc& zZhpgwV)OZ8fUj}@M)+>Klh~w65TtEJr(Jx-$oeEb$aR8rQfA{tFpsM|i+w5Q`h!6P zyZJd6PGypuj%EKCrGQ>(BD&6x35tqUfGjd58^rn=r>1qQ4I4_vX+89tztk zhmN@+#pA2;q4Ggdn5X--y1$u~TJVm&-@xW2Y~DW5bzUaCj7YxS4paBTAj=05St?Ov zFW?zrS%1~wa1iQDJVSy+t-Ga~HcSbvj?*S&a40*Gl4(hhsq5cBWM4u=+9R*9Q?S-K zyNs-ocni>#Hg~B1qveAf8#aY%>_kIgZJfWj8ao17@t3q348_Jm-9``OHRGRfO624F z*ktrudJ7Qm&gr)@35vEIru-3#*KC(G;%X-d7oda=ije<{%g;}Legq5Ua%6{4sP(s> zLB0U&+>v7^Sz*cYLwYYku%L5ro(21+8oktlXaL6)1)PvqI48-{_*oIq-&5?aR+tMw zyC#6o+jD&8+!Ckq1$4Cl2{s6(9 zm0NKF5AenWoS&*2_Gd8W07Ti3-J+((uTPjHmaI{;RXJjK+QcA=Z|wdQHlN1k857`n z?BP-*JbcCkSdxe53NSotVpy~;hOBtQn-G4)JtHrZbY?}wJWAx^4eI}cn(k-u>jl^= zh+SI6^Gxzz({PD|?@cYEBL0R==SoHBfBavY`Tfcs?N!42@bBkLMIGY+^1^f(#~1Ck zcyO%JZb;YBsqmvN1gp#3#^tEUd$OIy1I5IDA*DA?lJutEvs=D14d?7|@k*^KM=v(A zaMCym$2hQIlT~)lBBRBGzoYC@>V~hc-- z^&pMaITR!1CFV=hY~lB0ahyh@;wK8=U@cwh!3OU9*Ww{W9G4Fq&=)ia^cYCVFHGKL zDJ9jFF@x)T`N#z6-3RpeMZnVZYArY{&??gUW8{`LBgzv>`xM14xPbl-P%OTI9)Y{S zIeBTKuAjxN@vZHKr1DpZI_Us9O=ep~&TzGV7!|;8Cr%Ur?MEPTKQE^RLdzf?zfzV8b>#~NtM10I@fG23MJ1P!uZg zq7TlT%IZI?*W_AHzuMSdG)K`-E{W8OhE4bq0T$r=!d+IGPd&mlv=7!%jCe zLr04Q6MX3isU02vJpU{og0qt3ue8&OsO6hh_+-Wk%b|cKeE`;#OwVv8a|TY};7Oq` z4$bk!n@Ov|g+<3KaqriG6@BHt#Rl;q1wVh5#seKY_bm-1O|%j&)AU9PRdb4~<_zj> z1e;N%R7|IQox?Thy;21oFny9|CczlD7}=8TQd%kXo3u^?b-rgUjUyj5MpojPD}Y2~ zS8|LcGZh4hxLj?9j34J-d3Ecx<1fGXC)jt+hx3m|1Rg2A&8ND_i(1qU{xF$m_ob!en^c5ra0f2cY#adE6ttDPSmAGrA7*~;+H#KZpsor4DO literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0726de84244e176e428f04798b96293347358aa5 GIT binary patch literal 506 zcmbV|u}T9$5QZnG(SX4s2-d0W_N)~V6OSMSFCWZ-osCt% zHk~ivL-+u`fR&A1+=PhHGSkic@bUdK`hdJfs7Z{7R>(!vLz=K_iC09kAVqElBo3(} zO39c91Ja;c+c<1Y*Cx|S3eBog7?kmA_38QU?Qze6 zR$)Df%*zxnumLzLJu)TG*gSGSh#KTG$=(w$hkGfVfc zrT2^3%@Fn%Z98kZmF~Fr4=+Urau-kt?2mXr<4oml$Kx>olvAAek3KiQRtoKR2Ov}S zytM&EcgTd zgFXMj7qHxEIH(#ig^suS=ZYq04wVYj zKLV8_L9;^TT^Fq-y(Mf<+Nvx=&lE{WR>-+`3g}OJTz?MuCj|Q#Tl@53a`&cbFVG2& zBA$aEIP0x4DoDIQ$M=}SqniSH89@YWQ%r3?^^h=pm5{iPPL~2l#NkWI&wXRTIw=Q*s+Q!W7PK>}9!RBCQTK3F^vhi38 z<|7jr+e6o|LTBol7SLb1Lx@^EBkYcRSoxD+X6s`}(*wPGIUjijB-C|RGZbot3u_k6 z%mK92(B_7wDb%#)foC`u0YHIoj39In_6M3BLfLFET>x%4-5!v)yJIUfZEtM$01TZ; zAHFqr0(~^*Q^WG0qUQ}w$n>VR?Q5ffKZ2f2doa{=Sk>+R97-3|W$zBgz} literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55d14042f2c3d4c17d85c2c718703974bc31c168 GIT binary patch literal 265 zcmYL^Jx&8L5QQhZ3rc8EXt{$|p-d|N3Z$iBg(A@ntZ^KSZN}qdX*dE`phbcXi3@NG z?!X6R WCk&hBpzj%mIgd?I8LG?n^x_w=^;F3K literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.LdapUserDetailsImpl.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55dda6329e78274869028731f821a44a234b323b GIT binary patch literal 401 zcmYjNJ5Izf5S@hO-|+9~pv@kDY9UBOva*B-5b1_wHkftnU^{G<0*PZ#a00jo1s(U` z4mi67Ofj1G-qVznFY~fEPi}@F#N5TugdhZY?a`#K~E5ZecY`hF58L9Vf0%laNKjEKGj^ D2)BdN literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.Person.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.ldap.userdetails.Person.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7b55c61260f06aae38d4a480c4b5cc3db64b340f GIT binary patch literal 656 zcmb7>yK>V&6o!u#h1j7Wgv$&w@CtH6Mu^yG}Am%N9Fl&iUtDzW>K>*i{nV3R!xpmXw!gl2mvl%9xF)g zH40^cnoy>^6O>AD*gl6jup5Gta}5XKM{-H}ji#(0Ql;O8@VG#gOIm9xjNtG_zz8q< z3vI_4Nw1`r$RjiM6MO;3^iupbdZLkGeJ(ggO?8TLn{Fle|F>^w4oJ=ZqnrJMs%H1g z?{DBK$#co|_*0jO_o(YND{>0KSY)GTeg+WYFX?Xbn-cT@xxm6iHPH~5$TN9;>H^nWUt~G_< zfotnd2RZ<+{{p=FV_bb^-SDg%o-ZZ2wwAPCf4%wklYHNSP5`c=pRuhii!0aut%mL> zOO9vB@mfPK4*g|38O}EvcKrE9*|Cp|%-yP84SV5iIXj7uOf(p0(JCFAXyiwe%`7od rlmyvik(sW&52NXF9gkP326r_$vem_GK1|o9_x?1PXN&3kbQu2wBT&sC literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.ClientAuthorizationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0edda9a5d7453aa85f5f1f2f9191fe01b693b047 GIT binary patch literal 16940 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClient.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.OAuth2AuthorizedClient.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9c6c667a11a6bdedb2cc73eb17a2ed12c1474946 GIT binary patch literal 3455 zcmcIm-D@0G6u;RuNw@hlZ5pg5lp4WmGgC#RBn@%%p^cqtX%b7U{*eF(mYdd|JOnb{BO2yGq$d*|Ns z@jJisJLi)>NP8$q))xgM3Sr(r(Y?m`n8ZTz?7yk1F zf1Noq>X@j%l$#>=S)_~FHVeZ=e-$2(GZt7k8?2i(>!!AD+P+|B)pqoH!Xg9O??qPN zp%hedA8cC5Y^u;q5qoOtaO2j%M-QfM^MJZ9K=zUhSXbyeHC^fz%ms|x-M6iQ}8t4%)-+k3<+@8z>-YJW8gti~BP?A0!cUf}RTwoG{ z&PXi6;${F@J^Ozn&PM)5Rn}-{q9Vwd#DQm5uxPf_l~qO}s-z)4RtY$unw63q($Py^ zV&=RTO6p+-2Y48knUj@ky)4gi#s|NSPi^}saQx%t|kBPr5mkv3bBBeBv&*ECN?T3eng z1#%O@7~B)XpQUd;ieVtFW)oMZso$b9M^%CV+t*`oOVTmTs9*wIJ)g*x7LIru8qIAO zIfNn~LCHaVQT_g$04it>XOnZdCQPz*cTc0d2TQEg#Xoud~nUo+p(9tg^3n!7#jn1fRz!+s5g6s=~zs?;d zW|^ei1%I#HO@9~at%JiZ!5nCJTP_J+g`qdji+#ANl7@FW6{)8ZF%7k{b=@O+HS>9Z z#@V)P`wjzc&m{J!acxC}J9#~%YrPDU5D2imLPHKZkkO}O9Jtt}4Ik4(si*oy--iG% zCkil8^EFVT*nZ1A^}%0@piVi`C)ipUiU!s6^XJ%RB_QBDcNd*E@FW7Q(<1$KwTWmm zX!~BC7s`4gfbOLZm9%~Yo~HqDE~5sBh@NJyY^*{PLle7E7bvp^6EZi! z^a5yZU;FrPxz{HX5_|e&j zBqv+ls>@1kAj_&Ekl5?kq{BLPDiljNaViDNm8g& z<`#$-TN3WJxdpo(tV-LpTBDYlTlEsZ4P6>P0j*O@SwB>GC|Y$a?yWNCEDej$tUtKl z=XQU34E7~lweF8@Rlnbuy}JAU_0OM5tCbHHKhi(-jLNbNG*v)G;}~!Se(dl1;BF!@ zih5Ow@9MHMz7Xv!qflKe4nV!$>bVCo?s# zM9<$5!~+reMVVEpDb8SF&lCnQV9H@)VDe!QfhZ12P0uVYDM~EK%+K>oDPa)u$x19s z)Xz!GOV+HmAJd}Fy zsvuMl@hFIR6~&X{!GkCDpa}j4dhj3~6!E=H;-+bd1~R)lGw;3cecw0p_$zGlCFESW zr1_q-oux&|O1$FA70u^nS=y?qxvZ>;Bbq5}?kJ5u@M)V&*{-8y)3iuKG&$$4a0kL) zT*M)6zz{{b(!R#6@i5JKzGVAKhB-2pg5Ab4yUKLIoFzS{2*{`borK7=Jth>KG!UcS zf>Cc^)N2@Z)0JE=`&{ZZTzPyQ4J1srZLp=Kbb*kWYKx}cKRUeXOk2HiNX)~|rZ{dH z&|Pm*+1yt!Q0u6yY@v_4LU5D#!mc_ju9z)wOLNoN!ZPj{4ZIlYafry!C{&9={eyX@ zJV(f}y z>btjfe0uq6;PTr9#HXN3xXhYD_qj3yovJ9gUvz~Pc&AQ>OvEZX@EON{Ou-In&%urq zBM!gTU*FLUX!k9u&AIb zH=aE=xga^Se5$w)LDZ%yC?F4Lt_M-fv_(}0xwYg=wg|uot%&es9!BRB`>*( zr!5Pq3hN`lP9NX#xMeIV9t%7L+iUw&(;8YxHr+$VYztAIYKwA{V<-3`D+?7}Hxamv zekCBit(Qczg>zh?g;ONwU$>s&H7BFnC_WXAyEj{b7W-)!2mpKd4_jlkwF9@`-nzGz zM>B;Qbzf$o#fSOz&qwf9fXyDp_2&~e*6%!fdLn`AUZn>~NYzm$2v#2rgEZ_9 HOZEQ&L^vrA literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2fc9de7065d8302f7d79b10750374640d85538fa GIT binary patch literal 5546 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 W1dlzt_R5BDFTMp=1c~0BuKxg;)w8Jp literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9588433f2b137e0f14b3a31f403174e9d5d2a4e4 GIT binary patch literal 3632 zcmcImO=w(I6uy}>X{Py4n`o;IQX^<---|_DBn@%$W1ITgN|Pxx{)9X4-I=+`oA+Mt zyOT@|kt|w}LJ@=%#gz-83s)joTGyf!!3v@aU3Arjh;&ihNb%fz=jG1NqduX{Vj%b3 zdw#z2o$s74{zPpdLs_2{j4)u-E94n2ku{&K7$LFCjPiBE$7NnTX4ozz9yiFU_&u8u zXX3|a^gZHC%a7+so{_LfoLO<{?zck^`wy?~N}(1D^$8=jcR8B2z^&Qf){NYm%B`u~ zn(+?DD-0cp3*PoUPAc5U1c6I!%&G6mm~xl?So+|^4|gG^Qz*@8iG&=N0x&bUj90Ny z=F~Oh&9k{>Vsq3Dy_B#KDq^2Y#Lzq z4Df}c0ZYJVy4Wk2^IQ-KE_E@*hiY0A$wJU+Rp}(3k5>YKeJl~|U?C!?2IlAQdyM-N zdB8hmq4v=B11LS}RdI{5oAZQ2&}lA;u&^FLRCIXc(4>li?T9`;Z{oBQrXW-7*m;9TLfI zNq6zmm?v!eol7^LIdt;NErPJ3GPln?y&z1td4q*&FUY6yNNadoP_99L#tC6K$e)f%`t zYM&yQ5eBYKC32;twzdt8<~Gz0_gH8s(pTBLeHgFaRD z^fUoMcQ~3&?m*=bXGYLgIhk`LNrATNf1xkclP+~KPi#gcxjQV>6PCRUE~&C)`wjtaPbc=MaE&9vqrC1_wO)cb3j|oo;gEt3 zq}AzB3S8_|hM!YIsk{0`-G=}#BnmK5^EFVT*mlPp{p6noP^U%I%gDtt6b-8B=ieaf zusMM9#mDHpfhQWY-8Gw*tc|A4AnZhWS}3cH0J;}DnB)2pcp3-5xwIT0Og~L8udP56 z=!14%q~XY@ARBn>kOM}4?JI|b&3So$)^h@%dN8R%d_YR5#z(QwRZv;zbD!rAj29f`YDmz5k%OR^%6*vgY5T@&n@g|N}?6Yw? z5IbO;IsiEp^;5{E@-)?eLU7Po&t4EvH;wfgm~>i3&7m$$Fo`1+Mrx$?o{hx#U8 VlUcTarZUKAOav_Uyq#S?_!m_R4ru@Y literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..22588d03ef900718e19622e3cdc639d6a037312a GIT binary patch literal 3770 zcmbVOU2GIp6h6CK*cK>kY4{64ffPb4oe2ehpe3;MkA;g!GstR6BDCB6EQycV0=ImH7X{&_@X@cU^I%vbMEYPW=mbRHtE^9 zKj-Iu=R4=#tG8j1=farno=`l;HLMepE-UdV+dZXtTr0bVm{x377R63QGYxJD#Wr+J zp&1+)8WVu(!5}Ao{=(#jchyL^V_=YqqI}!)M?eBz+gQ&j*NRTY~#S z$vTc%Ik`OH#D!nRUmW=IRuU42ph*}d?g>_M(9Ein>@-u#!Y~!NvoLXzYa;(r)8N|D z*(*r^-vLNmdh4T)zridN=5rcCF&Ar4-F>H2*||T(4Hl&9EN;+Vps zQjlZcN#GxzXG@faC~MW^KzrvmymI5^H_nexEs}mSYPLk0$6U^F*UigEU!A%A!dQwb z7I*Y79IG}e3z?`MyW}vJ2|I=#nhm%>F|_&umOpFRwsST-s(=PMCAzN7l(1D3VW`@|fdr|uPPd{7z^oAk6?zK2^wv$osM5j`n=STF*5A>0T>Rm1RjrY~O|g=p@n!@!Ten9^{K72bXWh}+ z0qDxFroQAL-ta7JLNtNBa}^mHjPsoaauJcH->p(^yO&P1*iK?Qi4GD9iJc^Nk$9NI zBP1Rr@feBSB)Uj+li2G6GN6#_?UC0JO|>KRyXyu*LLciyKMSr671v*twTDz=MoAu^ z4dLys+iLif2@sz1m_lTmkcW7~dDtbOHMpRNjcU%qm!BmsDM?v9E9giEu?-1&kv-1L za)>T1NFeqKXf*T=xuGWHi%BJbjlLo%qclW7&rJxD-Gx1MBQT3AHB@Tr5wq}lQ3dRL zJW0v6L$8}8g&GAIaH3LqEdrJd_Y{uyjk}x$od~Cv22)e`*5UF_mfAV8Gbr)dSQDjm zwZjg%d99SyHJ+f2ozlZj`uuOsO6911U~B1awWMPAoF(imv{bXRkgxqxZy~jHoYd|U zCv6!eAxSdk1AX_AXqW!_XE%(|*P)t0L~N6rCEKL&D4BEE77MWgz>#@8)JY8ra7e1R O(C0A;w{*>Dtp5vq2bjbF literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..44ddad76c51b67db06255b07ef427af7441e534c GIT binary patch literal 895 zcma)5ziSjh6rS6VyIf2#QSk>6i>QT=%t90kPta2g39O!YMl>imw>!C=-0aL|=54ZR zw9!8xML=w<6blQrv@v2OSZGSIun{W@3mXOX&7K$qiwx}U{CeN}zVE$#^qKTpLuRyT zQ=1y0+H-~_d`X)QwLHv>fMu##2Jr+9rQiyv7Ewsu4lYE|KSh#S~*pCS4tdcsi3lJ zBRmkQ!=ou?V+=U5cJAtsT>Fjzvt$bkLvC%uMBJdi!y7TbZ}(Q-y?D9v`r97jO_F}8 zSu}~RYBNo$5Tk#wmQkLbI9Yf*u+)d&A$-a}%6t(EZ&AqT2I}8Jn&_J3pcRt3x4*iw zaI>@G5icO6&c6mXTJtC#OHx{N@`m#i$V3c~9`k)0#ynw`>Xa)HQN_V8^7<_ncEXq` z#pQUn>yXL5|1&w0q_B)Et{mNQd-naOH&_yvqlabDCg?Xgj9sYTIkfiVc~OK4mpnn~ sf4Ek=Kg76*5L2+?pwCS$c6qsIGlR={5J0@*l6CK@#mZpGr=y(w0$8;%0ssI2 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9fef9750d708d6383e708f6542ef442eadcce889 GIT binary patch literal 2430 zcmbVOO>7%g5FXn}9VabKp-l)8(3S>T)b0uh2a=-V#4WXAViY$>L_m1nea>$3?A^Y7 zOEw%(kl+duQhMQrgoIF~N?bs_P}Eb!sV5KxP6%<~zyTo@sF-;hd+jt>hDaIj`{rK>g!kA=#4(y)Zf8_Mup+rqOTaJ`06 z#ziH5E;eeOtTTn%zbxI#e)`ko?KGrHFhtrO8ghA{V1H?qy}`^-xx##b`O}ev(_Nig zp5!fece?`pmlkR0TY@Z)d{=TCoeCDH1%5F^p9+TCoEDhk(0 znXXAT5vE)UT zW78(VXp(7@%oSs0Oml!dQRx(%{vU=YF4Cqtp6NNoj_mS8F0zx9GE;&!Fep4`pJSHtWD#=8kvwobVMqR%=QIp^i9Ilk|5*i@Agn6Lq9ktOnuT_6 zSs^l;4}Ng-{SP-6)5u8)CzG)L4T)rbYz8*Je(jHkVn8efBW-<@T*F?#Xm$k&{eLUI zS=##HaWq2ycff+@R}1fMUHanl$+&0sQr6oTq!i@hnRCjuBTD;CU%{SuOF4;bn`4T5s(+^BH5_3ArU$B&->3|(W> z?!!0%oUy6nPu(~&OI}^3GzA}Rot?a2pGBbeN3|SZZx20#UJ5<8L(=ihR;Qkzk-72Z z_+R!D@7W_!-FIakr*NI0Evf5942vu#8DEDkT^zSg2ZDaj*~bM0WzRmEX*!1 zR?aTa)#*pB1+jobk(=@<=u2)^!3Ygtz;9s(pm#tAUc(+%dv>PIn-i zi{DcLPAj-C?kQrUS!@J~HE5U(Xv*4oMJY|2kN~~2AV_uzQ~w=T8tn9fNb<)|f(~GJ<4H!3zdqt3g_;Byb3zBx{f(+W z8(MTVDsJ5u{CSD!a(frLV^Dq46HRax3|3~#FP>eNoY@-GXB7;^TkF`DJZgpYG(Alr c3tQg{9gI)uOlYX!IO|`w0$IafU91TH0a@e)SpWb4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$Builder.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$Builder.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5db839c1aba30abe2da240a9fea886e0f82bb676 GIT binary patch literal 1845 zcma)6zfTlF7@a!<5kY>4U^GZ9u+ZR+F~$O75Kf}R#Tb4RVB%%iox2-uZ)cgAg*yp` zhT6mg6XU;Nukl~7kxC1#t*mV<{ATBtU0{QI-F-Xrz4yKEz4`DPbx460xTsn(5X`Su z1ZmJMF6x$~PAHgaS)7EbcE@r&Mtx-oT4hoRq8RtBQdC<=mBwa5=DAd$=vVZLXuw9p zx&s&NWpwM2Aii2^1yrGF8<6oaWE>-7gNz+6D4x!2F=?azBh8nAGP+=|lTCs>;#cva z(qqB7D`o)Q2j*Z-#ATiWF;}74{6x&mS#1F1tO1#GH_$6ow9z^9|0#&tuJoA7B6S2+ z?OJbKQwq3Bg`Vf56RD5W8^NWM8!@FtYMKMdA&2`FRt?P(K?33uMHK2YvW1Fyc%B4s zvWrO>QURj2nRcyj)uB^T=oZvvf;y>EZ<^4d5}nfF0fpJpD9}oarg)wDNzai`QZeUO zc$UZtP303OHqG&617LRykYEn!l3vra0>i9@iXQH)89+p)azz9%Elv8Q*ONRHY}Bzy zywDh;8Gv0$`byd1E=1!-O{qXmU`(5&5qQ*ccmsR9%6t z9)-Dguf92W{eE{@6BcOv|96t9FVCReFE9R#f?75zzz&B~nNN;QMxMWvbhepar|x4S zYk>dV`?k9O^CmRW_yftQ_V>>Z_x9g@`gr$@7IdozjMYE&AhK5hOd}|9Cv@7H3XNx} udc@?8L!~T74+Q9QKbMW-6dq6hX%6qK0WB&N8i^^9fLZD6Y03%}nfnjL-j5Uj literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$ClientSettings.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration$ClientSettings.serialized new file mode 100644 index 0000000000000000000000000000000000000000..14e74db3b465c6e822cae112c123e8c8e4eefa45 GIT binary patch literal 129 zcmZ4UmVvdnh#@k+C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVCo?s# zM6W0{J+ru^D6u3nKTppYEEa?$qyiBNPAw?`npT{_dQsnC=ARHI2F54`{-V^v(#)dN PfTH~TH1E{PiULLeyTLIu literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.client.registration.ClientRegistration.serialized new file mode 100644 index 0000000000000000000000000000000000000000..9eb1e5f751c68e768a4ea4bc96accbd37a45678a GIT binary patch literal 2471 zcmcIlzi$*r6n;L(KOxwF!3qjiic1j$JAk4TpvW<{MGQ+6VXnYISmWKfyYcPqEVFOz zb1X-0s3S#kBt(rwkv@ojfd(p4Bz3A3DWWtH%9|Z8dv{);EzFj0XWsYC_rCYuFMq*M ztl@^z4JVGY3>$UL+hSAcmJ0XqYaZgAtwSZoCQ2=uw^t_(f@J#{~HqR0sH`iE*!OyW#MUo`>|tL z43VzI2;Y^Xm#WLU6=(AY6tCLQvardC)I_A!hV+GA5Xfafc=rwy@7vz&1b9RXUuxlD zP0Q@b-K>}V{pfJ)sYno^2`grTGGN5~Y9}Ha&X%$vnZhYHMee-;7lt-?kl3PhBB~zm z_R*@Rd_jowr4g;jMJ{<4>PcJpRdP1DVReni(nA=t(F>AXb;KtA#5f4y!~H+@JQ2KG zieRbE?DI);=oP#8=)XG^7+8S`EgmFPK`O1P-xOP&2nc-T5W)LQlZ!Uu!emcvau1#I zR9Kgd#10#3ZSHgAz2>>aBQoHajN?S;{OZ{HW{Z542ZpgJ+M2zAqjEN3!M}crW)njpz6WH_ z{rrIoQ%2r{J88C@53;4#pMcC}O?=7dG33Hv@^;#uGOjZtWDaRFttBYlZlttGUzU<0 zo2>oF`Qr}G)#0Y#v}p{bX@rln67fhn-R3j=5GrQkv27ZIqNal#w#`$s?PRq!Q<-h| zZjK%5_wEQy&2pxt_TN4G)2kmJ@79d@G@LJXYPZqz2KeY2?7q1F?~L_34eiri8!JC% z7uR&2*_B~S_+Rt5N%+47uUGc|I7dkg{_*_O{{QC-5BGk4_Uq?^ra3l`lFpN}U!`gf N(3a4o>=h$i=YInhbe{kK literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.AuthenticationMethod.serialized new file mode 100644 index 0000000000000000000000000000000000000000..4a1d8a385dbf79b62e3130dbc3f2d1770f6c6ec7 GIT binary patch literal 123 zcmZ4UmVvdnh`~0$C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z5y(uMHMz7Xv!qflKe4nV!$>bVzbIAD z5y;Fh%B)H($;{7lFG|cS38^edWdH-F93}=v9|qR4#GKO95(Xikti-ZJ{hY+Sbp7BG RklEH11tkou?yi1e?f_V!D6#+m literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.ClientAuthenticationMethod.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f440703d99daea227994c12184af4d602a00dfb0 GIT binary patch literal 126 zcmZ4UmVvdnh`~9(C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD zIVUqUuf!230HiXL6H7Al^L$fFGV)UxzO=uHA6n@F3f3d}CMNm;h)RS(c@uylr+iJBCZEID~QtM=Q(oCG}tTS($ErNLP z;LVeQqBjK(dhzH%5Rc+P!GoR!=|RDRDB|CnO=3jQh0IRgoA=)LzW2@Ee-CX&LqX{| z*MwRGb0y8Hyr%Ry*KjY=0vBAxA}sg2p3>Ysz)LKWI6h=ecHsdEk0JLbDB2Stllw=% z+`j4FSWJUcfGk7Qq8K4J2ulkUHqUYq3Yj~?!odP8v8feR5!S!*5C4dgl6xprK*urx zfkIeb_e&Pc<)$cYFgF;71b>rF>)Nz#E6i*>5mc2gN`e(7r*a?f-ur={I)>AbDnP1w z9xg&E318L*-j<$8YdGd7S*%uC^MMomNhqJCH*+uw;$}&UF)Q^ zmwsIc4vTz3w7QjYNNcuWHYTrvF!=h;-p9|cw7(=6(~x2aebaxmHD0Vx*VI;|n-16Z z>o)p*@bcul#kCg>r2*oQN~RDtmk~p=CzlJgLJH=-%VSmzC3gdkIfAPq?Gb&BiHZm- zPVX4cN8!ZCz`&#)s>Iv2`Gg9bpjaZ{Jqd6WRqjr4eQoCQqcs~2KkT;EYCTjG+Fwn6 zx4lA)BppwM+*l^FkzISp?jU3|XFj=WG+3(J;VT)IMLZ8j z&^FIx#N&|W;Lt1KqOZ;r9KUhzXoIOPPYSvzvw~>pmHqjFO1?kuo2~tMQQ3~r84<3! z#xoUP@t6v4X-Vi`qHft&4a22pXFjj1YumH^q#J0mq@*3w|G(kM)jp(IK;p5N+TO^8 z!P4$;aCN43s;M=HP!0e0OOfRHJur7lSQY-A*HQwImI>C3CQch;LdZ^yj87b#wem@r V%pokPn-VECZ9R2cLsm9=*)IqemVN*L literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AccessToken$TokenType.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2af983f2fb1768ba2707b2f445d5b1daac5a2b7a GIT binary patch literal 126 zcmZ4UmVvdnh`}YlC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0)iOioTME)L1hPR&yRlOdG_sSIGil*7cp=)=HTmY7qTTEZaYla*MOsGpOVm#!aN S0y`tEMx-p*#`t*(V~ zh1P3%;)>#&9`4rHX2?j-C!osGH%qh zXyK~T%gkVyYDsHMiIkczS*SF!55C*`VTi`esb!2WPVckJH}%K^FMvBHR0$e_2f-Jy zB6vzN;x(jd0R7}{&#fg$FcVlk{)Zm#=suT57Y%6Ibtx7jv}L!S?woHQwC63|HZ<}7H(l1~B(%>y zUp@1n6hJ8?82)XJ-D^d(p)Pq=n5I=encmvn`|-WflgG0m;o;kNE+dr4{xkPCG8<$1 d)KkOu`I`U$ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8d98b95901250dcbff7f083ec8b3b7f892c1f407 GIT binary patch literal 16972 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 CmvlJ* literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2AuthorizationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3cadcc338998cf3caf13fbc3281c89e309fd6357 GIT binary patch literal 16821 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2DeviceCode.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2DeviceCode.serialized new file mode 100644 index 0000000000000000000000000000000000000000..8a382b26102dc2696aa13fd0149bda9c89f92276 GIT binary patch literal 313 zcmZ4UmVvdnh`}MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0)iNiEAvPIb;tN&Uk3^UBoshr*Z`7%GYwY=}0;F{!wuC^5MNVqQpoc4{627%=59 zF);fuaHduiWEQ0sJC>9%2>WCumL=+!Wag&od*&6FB<7V^`!H~178jSMrZ|=qGSo3J z`7m&mfD8#s%qdMRVGx37$w|yh*AFfM`OCVZ0O(O(kV$$Vlk|d9i>Ai5?2=aU*u(>L jd_g%c&<_j@>D|xjjroEiDvCkovLZz5z@jA#tYCWp>J4f) literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2Error.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2Error.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3b3bc1a11b8383ca2dcd8b2d9f1686ef7116f94f GIT binary patch literal 159 zcmZ4UmVvdnh`}VkC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0)iEh@?{VgLiC93}>49|rD})Z*l#%z~24{JatdA)l`6;P|40Q~QJ`Bu2MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0(PN=++DEzStZ&rZ!d_Eh|ZY!m|+Fy$~Y zF#9lYrdAYW0&Q_DDPa)y$x19s)Gx`*P1X0zD=taQE3x)r;K(d4E=^5wEGcBDV_@=O z;3@&RCoD0iG_{052%;q?F)v*|xCG=g>xu%PS9w7u>48kr3r;PX8r!l5Um4?mN4)XA$cDF+)8bB literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2UserCode.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.OAuth2UserCode.serialized new file mode 100644 index 0000000000000000000000000000000000000000..a3fd001c78683ca627a4eb914cc5af5ee59ab26a GIT binary patch literal 311 zcmZ4UmVvdnh`~I+C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qflKe4nV!$>bVzbIAD z-x0(PElw?R&QD1_X}tByAFrh>ObiSaMGQ7Xo8p*MTvC*nTmmsIBtJVfj{yvra+nyH zeHb`XD+)4;Qi~l+N*IKFvJ%S@^-D5yQ}sRbic1pnO00btI5LZiOH)%EO9~n47?^w* zxJp2VgeB&brj{@WLA2x~=B4Wgmw^e|@Pa2ARu>5Um4?mN2k_?EwIe>umY} literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cd379531f3a4913e7889a67fb19b983848cc4a3f GIT binary patch literal 2008 zcmb_dO-~d-5UpKU`O=6+Aez7li6%0W7-OPjgJ3{O22hcUF|N%_v)eK|J#^Q?;=%9_ zOuTwDCLTQc127&rarHlV@IXA67^~-Fhb1G~ME20TJKa_9^{ZDkpMO9}D_E4OYUxmk zpt`PDoo`FEVQKC*l)xQJvIf>}TCP;w;(-@R5umj^V;-7CD)E}3kilHjt+AlWA^H^k zA`~6CWP)2qp76~E*NCv>5Ttz!(oP}m7}7S7b_!|dKqmR792h!=qeB^Jj<9@MKykvU zW=MLOod2&^LOzqL-^k^8!idTIN6eH0xzY&domXs&*$ouFy~skkZ$Cp+Vy%H(Z^9cW zIWXL&zyrkse7X~o1T&pW&{oe@3W6JHOP(-aC40cdn3_+Ow^xW#P^II8ZO7@H;n?Fq zuj>mQ;DVR@A5h#Aio2K{IjeXqbxeMxbMhw}B}+>D&S+PLWW+XMS2)sENh3oZ@r!DG z)hKTn<*obD_lYZ2M~|-tb?J$9!Pb0E75Vw`(;qzSnJq%WfkHhhNfbVkg*zhH;NC-~ zYZP#6Z|V7w8i{JDls{z%`6pHdSu!UHN;TgwQb&H_0Z=ue(JU_t0IVpgPjKP z>C`Y4B)gYQ_(W_ox=uO%Mc0^!>ROK0iPUx#nsDVjq*nH96nWe}suiU~xSkiA%Mzil zMFrtbUR+0*REx(Q*COqRylMU9NSmEhoo*v2p?1&*)IhtV?+)I+-(4klk&$m?M*dgt zWX~_p!tVZyUt@6#xd_8YhF*3op1@=Indj;u?huWkLpA!PYyX;|5n|HQbcxe>(WTO5 uvUNKU>6DDM5?4wpgxj4DulVIQXX0oG<;=ylxpcf~CQXq-gMP&<<9`7Te8Uz1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..029e2eb8cea1165d244555675bb26a8387cd2f38 GIT binary patch literal 1469 zcma)6J#P~+77YRAf)K$yyNRiDzS?ivlmX=* zAh9wcBnC!)KoMi7uKWiEhKd0R@%k>8YpMe!gLCKi!;hc$dG7NMQnrTp+B7{I85uS= z3~P%WZ8kkCf{u}}>uJ`3)^#t?MtCCRk(MEND+_MZE!xP}45SX9h^>yWK;mCf70HB8 z&N0rV3o`YHxz->IrkwU)v28{>AQgSUqB);TFaRUhJ0R>9c|!_5sk&na&F>i&!qeSI z09kNw=`px8g-a8-)WM}g_y#TTxapzhedKF+U2-;ordZgds|YD1X>TlM8Zi4>Q}gwl*Ju>iDL zCgadT!dhDKZZv;8(bCQs{!h8*E{WAqiP!Odyb#BW7%m_IMl_`b6DzVI`LUgAl4B1; z=0{e1zJweYLY&BvpYk?Sos?o!(2!Uff#xXM4=sSm-l9}=Svyh!?bN19H)WUzmZn8w zJ{3#@Q0{eCUQ1+#*QqB@c#T>-*Lu9xQrR`ovGu%@2Hi7za6yl9g)MWcwEu tNpJtfui3;x0g&pEk6xBG7u#w!zw_O81iJ|1{GploQrf@lU_{XO^j{Y_0mJ|R literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse.serialized new file mode 100644 index 0000000000000000000000000000000000000000..00a961b37a56c0491788ba5db40e9db805c51052 GIT binary patch literal 462 zcma)&&rSj{5Qj(pBoJ@D2W?`EiFzUg4A})m(crP!9hd6vwoV5{4?dBv<~!If3m8xK z(4>=ezTfxz`i8b6m>9~0v!u)HkyL?ihMtAPWJQ|ag;6VB9*e{f3M^A=bjjkXABN#F zq(2mEQ{JGnrgR9^Y2*!P#n4JjiVR2blX_J$S7jz|Ie;!=Xd{s!hSS*d^5upv z17B{i!|=~9I3!FpVZwK$U*HoC{7%P;v3jhn=Z5UNguM{P`=0#U_ZM%k)%0Y)Cn0Tv zcTMhAHUm$n2Tfn!E=Xt8zl?^HXw1+Z4dTW9Y%!TJbgswK>HHy@Gn_4%tviP_$;5DNC>!Got3{{pYxdhzDLLr;SECROUuKwgGqzTfYApUL)jn6U;fX)_LOVPrnu zFf0>OZ6=`=NogcL3pFb-y$~kah)_$OghMI=en(G4{tZQPJMC`!;Kk5P6qA`nI2v!V zrz|Q_s^}&wdX<68{~ggESu`xcVc*5pDNtX&@*#+!BdS6gVf%=1{2&NrCZa)Zk>%Kn zp)IW~1@Ge%c;OVY=vuwUR4EXS9Y_?*$I&{vk$Y7^4CYqn?g?aPn<)`kMwGVRu zRWY6ST?6Uq=WiQ(`&TOKe4BsYE}cKs*n72GA?5PrI*RPh)pm|Rcta~C5|lc(XYb~j z=5j-_krG7a$GfdxxZk>7($+yJe0>Wp9sFjY)XQQJGUM#sGXlAcmPLOk_c;u zh6_W87Y{XmcF(lF?tVV;_)7r(D$FX)_$qUZXyJP zknpC6gj%D#451m2%$xFli0XGRv%ZJmUO_5L<_-}+^v=>_zjP}+qM7z literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.OidcUserInfo.serialized new file mode 100644 index 0000000000000000000000000000000000000000..be89d912a67f9ce6228c166d0c1cdfa18daf42b6 GIT binary patch literal 328 zcmYL_ze)o^5XR?D&iJR$H2MPCZa}QGFen5Ar>WA2h2!2_Zq4rPIlD2J#Tgv2o%Ssn>ju_{M7qoJwgv2Y|Oto%$^ocQ8ENXsOw z%A^>CGIYfKGPlq~tYe5$Sd|);aUQnPJAA;-#4Fvo!0NcJ!j}C-Pb_-k%xX>2D_gp~ zVQFlpa)q~=g7@p``PYB9PMd*|xraxH8hm$&r>Y!Nc8;zHz~TJzdRxzb0&oSJC?z>J z;EcFtXfK(6chdTJecQQtUxBy>8`@&lL+LH|Vci!@uCO|*tCMbXRy17;8i$NLBxF!& R5A8;~RHLahg}0a*{s0qwYyAKK literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser.serialized new file mode 100644 index 0000000000000000000000000000000000000000..62cc96f4be13e82d1896b91afb4ec428b2d48c6d GIT binary patch literal 2051 zcmbVNL2MgE6#cQ?I7u5CD6|csr9>bh)a(kVkVq;OCuynGrABqbp#sWecbuJOyt~Z) zB@PFa16)Bu3KuS1kT_IA;sWZ0B95GTYDEi2ZX7ruBuXp(pRK)d8Y&A*{<}MW=FR_a z-v4v?ci5F0n2*hhlO{$*D=j11axFHiPAdJ(C|q}9kzx3Pt((vTJ$yL$G`34Qf8 zEx178`o2ulh6$u0rXDWV+?&0t`tuJz?tkZ68A_*MOvfTPC47uc9Y!%UG7V!LbdnRV zSc>+njnH#~{#Ar>nk^$#$zGz+>04yMU|A7U8;3r<_Q~fPOCu3?ye=$*vPtL=} zPjCNqI48tM*uUkFifK8=JCa2E-_X}DZ2s~bf$;v@Xd(ZV#g8^W`|jIgW%4I$dpPTR z91J0h`dU!|%&4HlX}_N!4Cg}#6+VBO(#o_xlE0T#N>VxyA||u0t7Bj2Fiz2>;Y=Dr zkoG*sEeWXF(rHSw`PPS5rlwDSLt9e-;}j=AI63?5aB}Ah-c<=qSqo40d`AyjUkB{? zgtd?Mg$NIvc&R z>}|)n1KeMqwiY}X?Uv*^4-9+o7z3T%T8I2$oy0UhN30#YU)Jm#XY&x7y=?ZeIml*` z&EssQ*gV1J5Sznnj<9)(&2$Gy0gd|N!o{WL$#Xn3PSn3VFcFseE$#9*l>WJJ>avwQ zNlmD>O`t;b9v>LBww$7&;?5biO}vlUQPQEJlBezk`|_G%HM;dEMG$1xZOT;wN>|n-Dcp&A&yd*|xt5Ymq}O0?ajGgL&|EYwy{fT%D$BCtAL0h+P@%Aa@F?Vq)DT7h$Zq d(0KjiMI%LENqq@ncRsX6btyZ&upEAS@n6F2h>rjO literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..a9da1af34f03426915cbf3c7e00402a3009f1928 GIT binary patch literal 1313 zcmbVLzi-n(6n;sXx+yL6XZj-p5`vA|qGF+~1Zhjvh|owa1qp%RVqcSM9oyWU8#BPf z+zp9;0I3q47#LV6;xAx@je(7UfeD0o@6yl~7$PG1vmL+pz5BlVZtn|Zm4wAm)@&6? z5!5y$Yw%_$w`|4TSPK2n4q2@0)3zH*Zim8i?O1VXSMX^aABy-fq`EhSAKrzXkJr+W zE`ue!8{rlYG|ZNf-1&ptX_GrGa)-zrB6o5(PY82qWPGi0`o!^^eCjEnh1VM}s(SsSw4za}rbMeAqs6Sx^>c zB&4!1BQdapn2H#gI)RY*6Brl}0}|rdX}GE_sGM~6-FtqYzxVm`tFKT}66S^MxGIq> z?zAQ8(Y}zIuA*TonI5=;q`EufhC)&|RaCl*v`td3TMZKrFaq{*xC2EGDnx6^Hd0NM zhU4CS@{rV1&3OF=N#;DL8Z?2xY=7RT8uPUn2{gtK*XcmR$q@)Aai{JhcHEiE5~O|6 zV7ms}T@akpP%{y$3qjly5ocg!_NuAJ?|NTtX1D|2|PL|90{5*0VRSXN#Cm`p2-} z+O7gc?6L8GcFTQc3}>t}uwueN!`Z|2U~25KfeD}|PZ@nz_ZrLm*d$uP%q2UP51x}r zR?JY%Ktr|F2yU;;tOx$mEt|o1n*VIaUYkFBT%Yw4POnN5YZ@KW4|;S$3O?qhq2e#J WZZ54$N+L_~43Zdy`ltlWEQ{ZvS~~*( literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.core.user.OAuth2UserAuthority.serialized new file mode 100644 index 0000000000000000000000000000000000000000..7e4a1ea71126c00e7a2015c60d6e8091f37bc3bf GIT binary patch literal 417 zcmYL_y-ve05XUbm75y0akboC}HI*th1_*_!NTG$c89+$jCT?Qt#=*YOvhX%Y3_L^; zPr%AMFfcG7A?yIECChjA|M$N;KfOayNpOXX9Fpt9nACug`J=oJ!x4UH=9pmUU1m`qBCK9#jCu0$^AtM7$b)}Do z$8Y>x+_%B*rQbX3B9t3l|KPOmo}K&vC&-Cv literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.BadJwtException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5c30d3947e56fd1d61a2813bebccd833cfbb059d GIT binary patch literal 16587 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 DHe}?M literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.Jwt.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.Jwt.serialized new file mode 100644 index 0000000000000000000000000000000000000000..06f8ee1babad6d1d3feecb7b8b1dff1079308921 GIT binary patch literal 831 zcma))F>KR76oy|M(zGQNEmR!yCa#c} zI%4!1G}!P+Ue9;gH|v_joNu zscKhwGV4RRC3q-|y$cVZkQtc!ACEvA!Rif*h6lJ@cfQwkN5qg{p7NmR!-&WdX@spK z!jU~+l#!?{#TI#t8~!8KfQf-^v+HZyagClnuiNSRhuOk!4~mrX%%M4 z`3rgaN_UvXak|S0MV^KfqdF*AH->N6>3r~|#g9+t-h6mCv`b0WpunjSYky%~ZnSC3 zgf%t$KbYgq`n+H6u73G?;{IjN!6nNA!c+?}vFBx|=$oO&bUkkq$aDC@jv zLxD&EqM%5CB7qPI2trUKAVEP0NTMi_5=TM#6C@%r&S65Y6byrtc^_%||=fsiN8%Co}+=_zc=t$%?{F7mH+=+d!9R+gI3Ej3F zyVf~&Qabxi%ALL!*8FI1GmwE>4<2@95H<%UJimpH^>3_w^YMirzS|?jL?kXg=8n5g z-EEFKhucjVG<<{j(pTr~UaKCvK{ zu6KMmay`Ph^u7#A(lJo?8-7y~$)$0-)ryFqUo%q2QY=!#+A^qb91LRFJJE_yh(|>Q zV1BC|C6twBh78Mua?h@-w{QRS@@<%TO9=5QnP_FIp~3)n{;3z%U;pPPdc?fj#GH{Z zYPfQ*SWpj|{(*Mms2>fA^S!zo$Ah6uraM3uhA8I@it}ndbzt)S=+~|DMuNI;VJ&F* zaxAQ6TEbd8gR`)~EqD4+Ov``?O|&XPRK}#3<+fT>k;H+Q=kzw{f)QR>{0F@Tyy`Z7GwSOA?B$koG(&ZiIkAlW>||5Ym_Q zqo!MTM*XHAxiXBLMi6_>?&K$S0=G-Cyx6EY&(ouQo8vys@sw~_HN)ai6neDi!bpm>QzK{@me6`PqYwLWyDn{MuGi9R|6J1SQL;+0rc@T)ttFXH zk`x7aObf8Sg8)YMU9Lw9Sc;{&7N!m&E9`mQ%VYso16(G>;!$Ng{{XqLJKcKQwo1=4 zj4wqeG4>`)W1u-oTZ_cVwdhGMOt|DZh!>1RReY_J;#@ECUFjb@dd&ASMtMJnil0~7 zvpbeUkm4dm>u?xKMQ^WO!S=8|9!4vtgRTdnD2$9v7u!Ge^e*(mW{sSGNPA-!dDMeV zMzWc(dpQrBl6fx5%VwjW(lTAzL8iV|u(#2wleYAivG-=1%sWOSTky42iaCm_h1B!0 zK{_8_i^$E>9%B#V_qU^nJiB&0>=FGq87%%sf8@rlIaWKK`i96Ksgvarr{LH2v#ad$ z)DGQB1Lg$H@$k4=Y2?(!25R11N@u5E_eaS`HAl0A)cn^>)oqm0E5&?1EsnZ45a(>Z z!P(?&Vds7>aqqd2xL=eWC&?5PLn*$ZK2mbf)2#qI6blJj1gYtgIfT%{$&JJC7LkH2b8Tc_ZJbC}$r#SBi9 zTBNuzWvAQB#CBV3#CFYQOUmY0yA{w8;P|}V9e;ujCoFqM3AvZd>T&c#K}Wtx&uVT9 zzS^(ZoDy$$xC>4x58lfNvcjl;%nh1VaxOuQS4xT`#p?7&euSC#0b81DiiS+)-Et`w zjGew{w2gqLKco;&bH&-Svb;mjd?g>B5EzH{uuuD!{9M7jqNVxY+m$xR92{siM+ev% zhypR=<9<|43_VUQ8jp14*2!;NZdzz#6-H`_m+2TG9Jwao-Z{e*%7<+^ zFrgc02jrWyR_6zaF>Fmf&%6L00-y+OxxvGFfnAGh#mkMt&m%TjwV2R+7r@;B_t*%^ zf@r?aAlz>wq^ByQ7PYhk<0x3X`3u@afcM=dD!cHO*US7h9GKP$AYBD z`0BN%@_<1|=bAxa9q}pM0pU+fK?)8Gm6K0=gZ7CvKlY*kPRW7Ul*#b5({xC&s#BL< zA}cc6AVsd;U{7bS7N##%yg6~SG|4eA7Ert%d1HY`(Yv_=_J?&G)o@+Qi;Y^Axys9% z(;Axo$SCpzzG(a+wPRCJZ9$*Rq2uRC8)0BNgzqte6umQ?DxzA*H0;L5DcH4t>glc2 zs@AhSjO$h$jQjP;>h-pWO4$&j4KNOnnZtKjM1V&C9;M@;GwB;`(n>v2SZ<~(J7P8z z*x;X@%p5nOBPnyXst~?Qv9{S_O*`YK3o~9))S^wXmK%Vd86B==1S#&Gp_zy1{!R{TB_RlS+umt4?-(7QWII_W1<^PNX1Dn)`kpH+ z{as;1SM>3KQZ4D3jOLemf%(LxA-QUm8TFH*qmjO6Z`TR(yI868fD7^+yMrqDHG?y#W zx%5SmJBego)qD+6R)*qCB!=jqHqBa1i$;`I5Bm)|!71znC)<)Vr=I^3lPgjt+8#xP z?V-KS;z}`B(=8!aS=y!kZ>Vl&Y5--ECqtrZY7Lz}q*;HVVw3tN*ELWgC<|HDf9DY||}8|7r=wkS~R z?>s_0N8+q2h?DNHbo+tmE95NvaY|Cry=lll(I#&|X^Ij_#E)2#bZh*o4C!APapxtJ zOHg};NzTg)au${)hVlk_tAq$GMzsFKAeAjN+GXf}9pDXs4pu~$QZ&AP4v;ssZ4LDQ zq6CQyfYx6Eun#F!)Qq(Wa=$KNM|wo-DS$7gr_;CBx}x-DHw%LP2v*CS@=3Ty`!zY< z?QoAByfpyhGvVHb9K`~H3j5KlVrqPS-DWXujGB+iLE#%V1r>aw`Eh_J0KRD>JcAaV zMJmI$Y=miL$j8Yb_-&g4pJX`}Mp1Msp7RO0A5{?KFv*;(pu}FH;BR2CtBmAN;p=I- zE2vvqU%hU#XE&K+|K-#&)bx*;DHYiNJgd#(bwu6epdPjQ@b!$XsBLJWyb)JHa|!dQ z(ifesc$8M@)Mesmv#YQ_k}BW846ktoF1q-&vb>|5`3HLTRwl_@`s;4H>5WmIovNw6 zGr;84MV2y+2Put17d9PbUp7T=Ib#kju-hxM0A@puj9NI&Hx)uJi=I+Qi^=->pWgAH zW;VY?k1jeV136~pVTbtEW$H>8bW@H;K}vPFNU^EJcv=1Fi}s*aD%D$ZE#-PTVkB6I zsbT_IJ#A!!^0ZA}f~16%3b8ybTqTX=a$KR=TsQ4RjYjEimC%%8MOibmD%#CljbVZn zn(={Y8FO8*<;t%-?Tqk^R*u@vV?7H;pt2NT8GdF~v9b>O z76UBFAkgf@*XT?=fvJr~EGb0y4<$u)n(^8+%eYP!$5}Fo3NQf=v2z@<_wKoTO3tD82N0u7KJ zq*-#oeQu`KUc*`o3Lnd*DA4})sEPzay9zd8|INV07={oa7!m7syd_V zHh}(8Bp9$t)8mq|R%oDKFgUd!rY+}HbTvh4pU#V_&y`D8xrG1um=?7EL z(eFs;ZI+Iva3*+3NJl#s{$2c8-9ovN^ryDdtf<|zP4sxq3NzsVlio`EN*~XZli5!h zIC}fnR7rC@W3zdU@?^0vE4;9cW5rZ&ovITLDLDVEjYm3!S4thLo;_8f>NTg27pRGB zlscrixU}6^DzV^-h6Zw_36Z_baAH(k7Zs#WZt~f@=1# zYW6{Iw*w3&O2u(HKrIM&Z_+C0Lg?LmGAY5>Vq#goDbY%0hs_Hj@SU}C5ON%nVm5NF zgc6C>X&OtPROBS$>Oi9VmbOQ0?0gBQ$aeKR{~rDu*#(4E3!(5x4G5W+XYZqhWk@Mx5RR1~Y_M6VM`*y}lDC7e zjW&W`LLn2boiYep@WqG)AOh2knPfx)4 zApjR3697Mt7G82GLZZT0ZRjq^yy^!h00IvbO1z_ul z6xmh9tUDESBY0Pos5A>n-vxLN;B0}ev|`@XDxh*SRCu6Ml1j?%bE(KVf z@F)2)#TIm~u{$3`6jQ-^QX@@$0wYzv6yjAd%Y5+yO;-V24ZtsAa#8S^uQ))GO#qt# zGTHfQDh0s54ggytJMw;3(v4{6jb$$BCbLxOWfY{)D%&&3b+p_90M(?aPN?^B9%FLV zm44eWUnG$YPP+m25J>kucs|TL_n|YJ=S621Nni{-2yh5s%FHbg4!4-!@WlTC=v2*Q literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtEncodingException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f9b8f14f8f7b8d2e286f8a1fa0264dd69865ae20 GIT binary patch literal 16594 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.jwt.JwtValidationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..212b70426110328919365ef0b88bb90eab8f122b GIT binary patch literal 11427 zcmeGiTWlRib*`N_cG|Q}nnx424M}d3mZ+PgdDo%Mt$mX?b>iUbq|g_vcgOdxy?1xJ zJJ-Gr2n1nPeD{dNECihB~ZWmS1G_bGqba^k85Ak z{uO_W_s*O-?>Xnptj=N{rcU@{B z>`*%-hr1okF2mveyy2YZSc*UN-clxoxdj*Ou$f4nyUfq~z zdCX~2MeCUl^qpLN;L<+?;PnZhf_VAL*1NV0-S}b-VzLqX^X8OGU-|XHT}S6%_Q#%j+^|2n(e-G)K_QR&hM#*Z|@#xuBbBcyz zEYNB$&I>P_j9z^Y{zB?BWvrzcJ!=oQ;4-K-6}m#a(G5Mu`wFEM%Ams(gHRz zJyOUuF_kO@@-xNJF8sQck*j0abN-C4GyiNJ)C#G|==jtO1bZFyg$yYEyj=&F$pA2N zgTOW6`%K^)mCmkDtMF;yWF5>>#ayJ!zgGV#HL=n1J=?*|WV$CH{*HSbNGHN0(ORSw ztK_;YZ#wv8$Xftp@vGPl~#vvWe^GYK}@arfeeS)e6)bkewv<|+zLa;12RVO;7Ox+GWieuLBzX##-2^WNJytKO~>(r+GluFtyp3)AAkvcjyLDe zDyM|_Pj*B1zCt`B)TMO@XI?#xNXWl!v04U{h7$wRaU)BSdX9*-XoGm=U-p!!%`BezWO&k%4uLF(DKL z-f|v(LY!Zp>5*P_wa}8F9qSxZ&EF&?Uc7XmgjpLRr$!9pEA&83m5`HtO0Y4F3^^vr z>`w%mX$1~s3xo2=V9++?F?4%FFgXflwRl+vB}%qSO0_D$uug5AQXCj3x}cQM;APg2D+HCQ|# zB_HIO78%C;K1pHyLY&K)m+(Rg^7Q>(X#>o`D`>A?<<`LZ0VSTLVL3MR9P~&y(3R;z z+}N&qU}5EEN{%Ad!;5%|1m-p(rdRXe}_*>-_@jS%HwUVO4B}mf};hm9MSF~bJ zRC2~%qB^LZcm|TcfKAF1z9FSsYy~jtVI^oxLgDYXV4op7U+Y0rjZpo7?cb&n=l!Eji>=eZt657U1W1=86?2v!@4-5l9@`P zc$IM^H*p$hI8fS$R>QHN&{sP~xueF=wJF~zd08c*yvo+7=|3qw&EeNP>^#JZO<2_# zeIf&nKR>JkRF?wy8V6uxXqlp70gOCNn$axO#rjVv-k?;qlyU-hW|1>T-Gy?hloHBD zHZEfGA#74Ie3r9_&Bw911nHnN>La@JLOqOVVWulPqBKz0;6Eu$pBX|*O668j?RUx6 zQJt+NCH_oK;&pi~>KN_J1pJxO;SLVK$orOQ<{E7E!GWo1pVAy14KGrgAHw!}&cOo@ zqifh$r%`LF>7;fduSqs9ER#*${mLVB+JqhI$bx4!9ZTmGvGbBBrJFx+qS$Bh=CI| z4dAzGT8;4_Dyz@(_%zg0P@<@wDE1H&_BKI|F+_hE(C^Hl2RszERTe$x1Qd_2%KOXv zL}8xpSL%K)E4APqd%uMZ-$wuMK$m%$@NLBO9c+p)^}Qctxiyic5{Bji9{rWoR}Btu zpw7fIBuLb%TdL{0X`$5#+Jp=aWhYY7EeSI9ya_~hB}Ak>@(MczYn`(T2aXbN0lL!q zF7U7NCUY>p8ujD4-%ogH?v(-^b<$*mSTW4hco$*DtZjlGCk$Vesj^PRH;Y{+cPvFl_>HtqFfP{xn=>SXe zkgbyu;gdQByMTmJ6lBGfuR-_`*N41JQkfO!@hFjtH>m&H6xz?>*XLocAa-dL*VV~? zUBM+1zB9Fqiue~c-76KLU;n>0^ZOOCmqYak@58Sz=!!auJ#cQsFHAGX*oz%sblT#< zu}Y^QRY$8;h3n&xWT3jtZCs9uyeAth9w;XMTS;6yNm84B*KB!K1J2pu;*}azj$UkJ z;iPdKj&WeaCadgsEizh6nCD##c%^=929S@GTGWYPCx9W&dV(Rjcb41#WRHhx{&Ws} zC1^GYNmDxD?5Sk-Y`ROY2W=w8x}U;l3r)Q>>@+iUYhBD_x)C zU=IfOl(RnuHw#OK6Xhm2bUC7X%zNWF-}G{7j<(|dAq5tF`8hrBz$&B z!u(z^Fj=GGI(3iVj5Me!3mOD^7^LJE zCU3KplIn_x!F9g8EkJsA13i8bur$3|3l0mEij@8sxv|4Y>vO zbP}6Wg+Qp#GKj~ol%+x)`GUc)od}kk)zGeZM`RZq=fl=iK9-9+rD*-}yjX`wv{!2d3I$9f-GAF;TdF?L4ULnIiWfkmDhzBRO!D_Cidd zVw(Y+IhEtzuwIjEJ@sm1bJ3ibesW0^zi3#8FA-n?wioU&%6#e}uA$ptoh3t>+rI=% zAMGxf;JZjj?dbUT@z3&pI4enhN;~z2El)SmqZunK60UL-(4-@h3asc3cP}=G4=MO-FKIl`Ax5Pnuu9(GCd##q3V+S1DjT5= zMz$38D{G~=xd;UB)fB%t!P-K^XtRP3&BQwe9=e6g#?*H$4J1vp0xr|kMhaDPimPTE z^>z-M_r^-abXtWTEO+meD(HgglRPsC#<<1EhHO`?l~Prwb(+&c7ACPd&&Ucqa|Mu) zY)y`_k{7j6x!MdEKhC}Q!lvhsJ@?G3u%3{ZcxdDc zaQEOBAYA4QDQyd@2ovq>}?n@>tGIYAZxlmz;J1ib8w z^`G@>5zMo9#qcCL&_mtGblz*cXFpz3%xvFj<}cM&?3i@Iw~Tmk`eK}Kr;h@d+k<)q zhiL>4{oP7_1|7rGsgVJjtg&gc3=V$pE*h*7bQ0KLzxaj0vC_3q+P! literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.BearerTokenError.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3ce7ca5624e7afec027fe87fe783555adf58e831 GIT binary patch literal 473 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..1e0c8c6a082eb5e8415cbe249a7832adc63382a7 GIT binary patch literal 684 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.provisioning.MutableUser.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.provisioning.MutableUser.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d93e5f83da7494890d3d994663f715c077a99904 GIT binary patch literal 190 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal.serialized new file mode 100644 index 0000000000000000000000000000000000000000..48f76f0f6bed0cba42222c21c6491332840725ba GIT binary patch literal 357 zcmaKoFHgik5XC1=F(mv6AweA&^fp0Y4nqKONl8df9d2podJEg_GCNy(2m}clhr}X4 zBKR150D?vF0dVXd0u=VWm*0CcPoFU72(Y0_I7`Y@W0EyqG;}5$7M>JOg_E`35|)}) zl}JISRuw3u=Ls5Cg=Ezjv5#ZvH4kHW_t(PmC}0a^rM|m<{3?6B+XT`a<|Q+!6VK=v zmhw~C%FMIU*`c)k98wczFs%F-TAC^whP~-Nl+a+7lsT>iCu&) z|AFQq-|uWVbv-tT*d+EEt+9yX-R41Uc^axm+p9OnZy&D-KxY|JAFgFsaH_T%<0I@O UQa1jf#IDPiwdb9O`}Y~<8#~8?00000 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2Authentication.serialized new file mode 100644 index 0000000000000000000000000000000000000000..929b7d477bdfc7f67662f3f3326f5b6dd0b920cc GIT binary patch literal 1187 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 ZcNnI>Cg6@aO42h_81t)aN=FAY_CG|5oqYfR literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cdc6b6b25920853d28136f0fb16cfe8b61a78e81 GIT binary patch literal 6302 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 KaRJFbGXERwNZkYg literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5c4c093b58a95e651e766439789de49afac55aa6 GIT binary patch literal 417 zcmb_YJ5Iwu5FKrlCWwX#{>=jBub`ydcS$^UoZ{~=(yCuv#HBR#)_UD?{uJ|VI!RmSlK)6*|lav9C2<e`l; literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b706114187c4d428a2e32015b0022e4bf436cc91 GIT binary patch literal 473 zcmb`Du};H442DfmkpQtUAs*r?u`*>u%779vFq+g{4VUEVa{^)DiI8{|Hg{2 zl}l7^YE#6ioE9upYP!?QY1LBD+pm}RPyb;ONHRDGY*S|yPO}H>aPF|S^FkxSWd?^s zw?=J+R`3dY&;Ns%-USsbbwvFW5yqFe1ZEkW?K+%X+z5|M86>=zen&zM`$AFIycwJi zm45JYjiP-{mgD7^)77u$IL12dT$}U?`!VsjSYd0Y!b#xDJBkv&9Okygy2)}A+Yhyg Br`7-f literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..19cfd3c8f9bd0950aac2b086810fee48bf3422ef GIT binary patch literal 736 zcmbV~zi-qq6vtn4JzcqqUmc3X467{=8v{^8MWr0AE`dkts4!Q-Kx9RFKpaQ##i*u_PqN?f)1LYIOAJ&Z}=cMO&rEr1%Fj&wdTYup=F*XEEqUuTLgz$|Yu&l`V~Au%uoAx! z6Ty|Ja-L8C^E*pQcb7eYBZy)c8WCs-ts}VFDQc36kA(5*H!Z5ES8fSQ)A5|~M%EtC zm?I0@|5LhoimqaRQ^4$50cb2-2`DU}uqRbr&Tkrm#jVX`n>y-qK;P5btt#NK$66^& zLzmpG=T)gQxhKW0LXY|5?YrOfbFdb{LJSLK;OaHT%WquBV_EHE_EfmS3+|mh+qtGr ze|f=6SQcsO%fD&;T=` y%hWqu^4~@OMg+^rqftDYARmQsIFE*7RAQQtAS4+2F3o}l2rfHW8igU>6y^_|8vX77 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration$AssertingPartyDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..55aff67094f6c4b9a588a6ef4a357f01ebe114d2 GIT binary patch literal 2621 zcmdT`Yj6`)6u!Gj-zk(92!bt@1d&R1Hz}zC&d`z;sf4zZqz_vJ*W@x-Q&gbJ@DLx2fHI0$U{riig%L-vz8!p2LDT^s9g2#8_okGlOr3GYU+#~c-Fv=! z&OP7x&e`308pNpzkR-*+sInsXy|oJOgF#7YU{vT1C;|#ID(@35jI2nFf(I&iU1=2D zkWrvlP?5qTLGm*WD2DOwGG0MpM~uN(pkh4gHx)v}3!)k}cxHc@bIM7B0m2pejp#6`ytx^l}b_&Qky29EdaRm3V^?S2-Ei2o<4L=yQBk8Hg7u zBvV*IdQuLCl!LJg{s!oo!>e^ph&~lRsa|_LCyNFkq<|3vsLS^Kh4-ypx3^=e2HWMJ z4giogGauja6+%GA%cj11ngkDyVi?#zP;}MkjMfTCep0-gpC_l?vTeh98c=qS07dA- z9tMk{^saiWml+`$0dpNf@^qFB27^p6mmzhvaGaUtrm`WQ=)qz!`6LAz6qPrrb-cxz zw?qN1|J*M_l)o=&0MesO4U1+51?=p4R>D|6t1w02MQP-)8AN=7?X^L zT_ca+To}d)Ugfv!iVaHyr(=rNqCYG{!ZNmjkj9v22b3S2RKM}?^S9_|K-U1RhetfZ zPqXYmi|}a(VRT3iC}eGCkN)@gMAz4(Ib;B|dM={P;3D+-EgG7l=_Jr*-C_CZz!@)> z8lRMN|D5~JrBYN%9N=0vn^U-?cul!BK7%fI_P-?RXj`dyB$rMs3Az*;uObm1kN*<>t0rQbn{jxKhYv$-q+)#&u9K=h>I4RW2#xNCV?RvAHx zBKi-MM2#L%TgUr_hJ0CQln^gs1ec{xHCs80CD&q^YUOgP^{E!}im&MF{~&`1H6fOE zDh_BO)NsH>sAM`qQDCpKkJc=9Oc`o+sXNKij(-^IpP)_kAy>iP1T8Y!*0$2k9mu(jjviCIZ0S>nFe zKYyya>m^U;^y$_Md%NMf!s(ex>%qIN>5{(7yH(qnW0-Sa-fa2L>f5WTDs3O~g7%ST z^2gsuz0Vn!-f?YZ*~XTPmlu5F-F`aq#F*T?QI_sTef`?m480qV&zu7u0PYRMd?9jzVNb?9P5U2{UaY019M zS+9GiZKYR^w`RjsP;Wah!&tF2!<=rH(nL0BdHn1>as;wl=iln|+U- zIk0ExhKmyxP+zRtIL34RJdJO0Z*SSVwIjROzgph9RJ(WL{8#q(q;Fb%(}{|fVTIq7 zKj%4axwoP8?D$=^O&|T)mUraNi%;VPD|XqMST!`$*|z=S^Vf`L_oO1Te?#iP_6HL1s-(UFQ${*iO&04tCJ9ba^h4x7455=vO9iH;;rkj`36I#2L z>uZ|tI=ZK0eP+;IG10dA^t$$p*58s2KHaq0(9J|%+B{{P`Kw(|CGHq@e3g0%|H{Nw vG58N?sBw!wN6!B+ZjD2XU@|phKR9G&4aXnjiXunx>|$GitGKizB!~V6OyQY& literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.serialized new file mode 100644 index 0000000000000000000000000000000000000000..975206a90cb913f50fc09646fe3e96077c778d3a GIT binary patch literal 5860 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.UnreachableFilterChainException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.UnreachableFilterChainException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..418c3b8ece1a2ae8506494fb0533fd7574991846 GIT binary patch literal 759 zcmZvaziSjh6vtmy^TU%E(P$AxA%%j)Zli&4A*dmdz?#B~HYsFo_ubwkv%8ZwGu~M! zf>>DDTlg2)3Ko`$jg26dmX`hr0pHx^_U?=W)4cb2-}m$5ADA=*cT37bqe&K7i$so{ zlJ-J_i6d#BhaGH&j|)PPv_(_lhEx`5tu17+-c3+jSr*WHfeIjq;cRP2SXhc#Jo-mG z8i+?M9yN|LjVRY+xa|I$b01#9M3-Q3S3DD;5=9nnDutO)_b78Y7PhMD(_8c7MeE&{ z0DuD)h5?UUVP%dL_~Gf)gWB!azx&|DAy^ULkFKvS)UO_#Ahz37cKld=e!X*Zx%2tk zDL5U&WFnkF3zuTA75OToisasAQ?x>=hiHt*n7c5-HLTx5eFtjBiezt_M8d?ioiSwK zSXby?YKdEO5)^O{5s+5+#g@OOYaN@sasOPRDRA zMRxd>*S!DOI>R@FBUCL%+b+{FOPRVcW;X9xo*)@M$(|6`{)(&DmcKX5aq~QYzea`w AHUIzs literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.WebAuthenticationDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..707931001992083b35f84271930084b00e043bd2 GIT binary patch literal 162 zcmY+7F%E)25Jg8Kg@ug=Sq@-Dq6Q*`i6+_(Fybog;>;l0cp|Un9Yi~S`Cjt=>kXkW zB%UiHEn8O|85`<7UyM-EvDJs^DL2^ZiJaO3)p}?4l*fN$L5j8(_${ad2r`&5HC`z$ sOC}M8S$4)7Mm4%B+Uoagp20*0Hzd>Y3Qri_TZJ%PC##*pczK97AAxZ;O8@`> literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cf2c149e825fef4417e62ed8e77be5c567df786d GIT binary patch literal 1231 zcmb7@zi!k(5XQ%M7mh&wfKx!HaX6%3+hz{Yx@{VU`f8Wfv@AhH98d%e2!?%f%YGd7q zE^ceH>~Qt;(dUU*AH>M8S z)qFe!2AOWyU{^bAMv+0AO>T&6X6c(|x)AZC2Wir)SX| z_``40cR^8Kg>eyvx~JR?t>)51Qq@%$D`J5Tw>WgBbVJIibyV!6znnT+vQP{80v%6; zwRD4XVYFr}MYsAus7DX!nJOGo`0221sovhivrkW7@3kuc*_7(EbG+EOVh}0o>&vC* zFZLg=RVj+HQvaxI?o!q;oH`hJptMdN{*vmT#wvdTeki7+ literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f8e27087821439f2507f952fd0ca5c8f1faf0c0d GIT binary patch literal 16834 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails.serialized new file mode 100644 index 0000000000000000000000000000000000000000..76b18216fdfa72d33328bb729ea933ab50e1c42d GIT binary patch literal 385 zcmb7=K~4iP3`N~(5vmXpf;Csj9H6T~g|=#tkPuUKnKot!Of!SyVNw=I9D@Zn=snnT z5AHxhkzj}L!VBBq|Jj=l*l`3@Q6XGS#unG4R@hc_Cmb#tGQ1WoE`)0M1}&SVVpCaB z6UK_TAk2O`s7ItMqmH#IXbrjP(s_v4p0_1cBb1bWUqqOarWZ7*j32`GSr>;M1& literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.CookieTheftException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..bcb7d655522cfd5b8bdd4b34e41faea36d859b83 GIT binary patch literal 11333 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 S<`<4W|LmXO+<0hW`WdQyE$S literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..cb6234b9d27a9463e637ae5a999c7081de129a14 GIT binary patch literal 16826 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.session.SessionAuthenticationException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..67ca836889b6f6cd5df0d36f5fd4da2370d64465 GIT binary patch literal 11233 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 j$uX8(sUS(j<MHMz7Xv!qh5JT*x#v9u&3HLoNy zIk6-&KMyEZTnwUvA+%d&1z0?wD8D2%8KlCs45<1}kH%Ghwku9d3`{-@Jb9_*Q01N} zB@9A7S&3zd`ZH5JXAe*g$YVvbZ;A#pP>KGU+iWq$HIu6ZYsUUmx9FvMmiV~Ac z98p{icGF3P<$o_V*#2Z7=~2Xk;G1pZrlqtvr)A!o@B7~Oz5TESN1cUR+P0W8RwbN`Ok{wBvdHwC>kX^O zPzP>Q?AiI|!g!}K@J&UsiJd&vNGF9!TJqv7iVI%F(TQzSBv#dob;cv37dr3qXqXmZ zPSF)m7+7-XNMK{GIH2y(H@cGPVQF9;Lt>lTt;r(#Pegx3v<*ypI{z~%AHBe0f2jKp Dg)>OG literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.authentication.www.NonceExpiredException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..e2e04c184257388a1e75712822dfcbb24fbee93d GIT binary patch literal 16807 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.CsrfException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.CsrfException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..16edb818a7ca2c515ca0363e0fd5b0f27480a41a GIT binary patch literal 11077 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 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.InvalidCsrfTokenException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..b7798b44b73ac581df264c2d6228cd6be8521549 GIT binary patch literal 11241 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 RHokKB#b^Hv=gygM=6`1(@xuTB literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.csrf.MissingCsrfTokenException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..171eee2bd8e7c029f5d8c49f738fd00b18ff2b26 GIT binary patch literal 11227 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 OzVOVSVBa|(&;JkJn(NX4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.firewall.RequestRejectedException.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.firewall.RequestRejectedException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..47de867dfe1d93043526ec3e4d4551e4226b635a GIT binary patch literal 11020 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 V&b@Ja<2%Q{_WB=T-#HV^{10eQnGyg1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.DefaultSavedRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..c35bb07a8605dd2be856147bc844caf497d69c96 GIT binary patch literal 1787 zcmb7E%Z}qj6s?Y(XCuu6&A@`;6Vhw}jll2sJMp8~OikkMgh|I4yV9KoX(T=a3H|^+ z0+<=wZ0J}mPsw&g6K0F|HpH*as)O!WXw;PTMOlYcOM~8!87DAVqf4S&31P%b~PTADC^H)tb|GeqOHW^|bTqoGjPvo4CG#TV!yy_U;8) zZTCE|j>U&Z2)*$$MFYD?>>$t+iu!?W=OuoqIQsnxt8Pkh=XJzxnpz zlOF`s(a~sCk-1K0w5lyMq>H+27S(FL+kEgLN9VOmsEqEyuM17Os$(i<$UEwRt;b2| zQPh>Np}A1j%p4P51KW&JiUgca;lBvrdFW&~4^>x*b})hycv7n9vaH=sHn1kSmpE<+ zp^6V#hjC%$rtanu^bk)2SHe0>o`rgV9r&C?zN#8oC`0CM?&-3ANZQH-Du$91E1Kto z1voi{WlF3MRZX=#(StNQgou175sJ$iASu{^1!c1YhfW5u16R@#)i5UzK2&4ZFm*}& zk10eazz{gH9mmQ7#WHNxykVq%q(G!@U`xkX0c+P!)EI*;$Fk>4{4Cq;4&4a68v&TS zd&8v5_rQxk?>+hAoxgq)P|rex1+Y7-<|S9_c1`Q6R)-^4N#&XenJ0y%Fknk*OU@2U zqM6mp&9%Dw7o=X2R_wdY-*8dXF(wotxbL^mW0w2zzRUMo4=?6M@HssNCAft06Y?)F z)xP#3HGkS?Vqm5?2~EkI0`FoN?XG*adfP@5Xs&82XHi#MW_GL4V{m1}L?5WBW+y|*y zn4QaEYQ~Y07VO*#u8$9K9Z0CfUY-NnLpf3k*U$r)p_fgtC#MHLc1$b@PbDS_y+{pB z3L~atCAZTkhFVyXaz*8R77}C_PO`w5czJ{Y9zjz<{@uhfLk;e6s+ypEL6xANuIGhQ XcE;2+Dcs34096gcNvLUFFm?X{R0i=q literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SavedCookie.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SavedCookie.serialized new file mode 100644 index 0000000000000000000000000000000000000000..16a8258f007c5edf03bbffc1677c1858dbabb208 GIT binary patch literal 250 zcmXv|OHKko6nqdE2pbc3UZPnWS3&|d&KRZRuXhi4jxE#OL-(5jH=Kw=cp>lLfLg2i zq*8VGhHeaS=|e7J8H~%{0$SSouojV)RWST1wzLotYgz@`R1{gLqZoU?HUuZMi#GHn zBo=qqIcZ2vU6RnNDMaI43caPbmK-yjryp43ut1j&6(2XRQb<5ee>P$;Dn@f4a J(7Aue#y>$WN(cY| literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.savedrequest.SimpleSavedRequest.serialized new file mode 100644 index 0000000000000000000000000000000000000000..58449b0e225938c89ba127cfa45d72b240900838 GIT binary patch literal 1022 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

!t&ypeegDC{?7ohYB4WoII3I3=MmUayM zXZfRX7|u$PSLvtLu;J-mcsb*RrAR=Ro`!iPPv_xG<|3TH!SDY(acGXeW7B2TxUm?R zB_7x+v7)J`=NrTyQt{+rS)(VH9q>GlpWt!SZAvEVXG#3!Jr?DA`LB-{?4|=fN zeL_O82&K>Ql}RYZJw`TVyJA#IXLMPp0^hTihER`TMwa23E0Ba_S8|LcS1L#nk^iG}7 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionCreatedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..bf05c7183134ae7534d9540df8e9b025d8e2087d GIT binary patch literal 354 zcmZ4UmVvdnh`}MhC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(c(DK5^;&(rfL zDJcksu$_xi6H8K4T+34PN@mu6liQU%*_(-hp`wVv4zF>^`9-O4^N`H~nh!Rt@Tss^ z-Ksa+NjA(esko#lF}Vb4DA=$Coxb0XSQl_Y4Aa5pvgG`{lGKV4J;#EAoXq6J5|}%Z zT3*L@xSxH<#K7pqz*&-+n_66wm|Fn!plDWNS)yKPNoI~7*b@JwtkmQZpI%NsiQL*1 QAgc-(7#OE53bE+{0KBe;S^xk5 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..279bb818bc01c5812a2aba86b0dfa51e324b1bcd GIT binary patch literal 421 zcmZ4UmVvdnh`}kpC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(c(DK5^;&(rfL zDJcksusu_pGZORCQ&U{aQu9hSbjc=d7P@N9#K7dkz>}9+4p&veAmo#kSeB@t15~Xa zTmrJi8mJ~eCk3vikfDx&v7(5<9K$1FQ5;%1TWx@#*FClgO=I0kW!qfq`+_ OqL?735(Y*?5C#C|2b%)` literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f2e8085330bec37cb385e2e167f6b0a967724da1 GIT binary patch literal 783 zcmZ4UmVvdnh`}enC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW8sRtkk@c%;dz9{36HV;?$y&%>2Bd)Z&8tyy8@rrk>=qc{ivN*GK**6E{Jrw_AEA7~W_gRRpCTBq++2{ghQWEQf$E{P?Hg$#8Jj6MvU z#hK}Oi6x~)sZar~QlOhW67y1WAR-k-49*mI5$3alCo(rQy(&4+1hSMbIVTes2q0&8 z1^fGfZLTN)2BtA-Hi3P2sd1aV#<2zZK$D{xSd%~=E@5DbcB&{SEdtSNK8ycg;|O`c z#K2Hdz`(%JR;^T0S&*t^r34Epz4X))B^{;YjKrLr)Vy?%RE9xWdbxXGR=#tUW0gy2 zac)&WLAI_}n5S1zPKUuePQJc~6nK7StHOo#LBb$|V+i`+n=54-Bg2Cg)VQvhV)WS@CLN$e~+#zBkZ} nRalsmJ7L~>^`ATQ&vCQ&pL)wQnbXifr{hq2x2u6-yLAr$lY1K4 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorAttachment.serialized new file mode 100644 index 0000000000000000000000000000000000000000..449d5b9a9814420db1f69c3f4be1de49b487a2a1 GIT binary patch literal 130 zcmWlSy$!-J6b2tikq{+=I2{dD3c7Sm@WpZ*ga7pWoWM>rjKl!!KvJA^SKa$ZO<}qw zwyI=y(T}OSJ!DKA{-WA27XSbN literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorTransport.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.AuthenticatorTransport.serialized new file mode 100644 index 0000000000000000000000000000000000000000..183124aa4e607bd6bfea05073e6e1951ac2c9993 GIT binary patch literal 124 zcmZ4UmVvdnh`}YlC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW8sRtkk@c%;dz9{GyPe#Ju8y{GyUgoIFYI*0@VCF);ctu$Cp}l%|$22>E0smL=-v WB<7{-2bX{>u&yX5VPGyTP67aZ3oTy& literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.Bytes.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.Bytes.serialized new file mode 100644 index 0000000000000000000000000000000000000000..3f268bddcd4691a3b16f695bb36970d33abfe294 GIT binary patch literal 140 zcmZ4UmVvdnh`~6&C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDD)OHzw3HEy%lIJQ8aiGeYifi(#vRKma%?Nm`vS_Gokd=~$~#u4&>iGiV_fPsNQ n!BSzZ*$cs6brSAf##2h7eke^p+n@hinQJTKoP95L9=Q(yPv156 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput$CredProtect.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput$CredProtect.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0222d302d6c70ca486e5530b9f0697b4089e9867 GIT binary patch literal 507 zcmZ4UmVvdnh#@1tC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDE`Qd0to@=H>aOB{iMsd*)t$%!SI`FXAtC8>GEKt{21P9{*;Gq0euLng-aN!eSj|3M{}`0 z%*FaZ*MczE#ri-O>mxaVL>H@|yUDtufU&NKp^{!fhT#APC=g;`s3>CK%StRu)XPcC oOV@MFE6qigEGS`+3JrD*iVt%Q@^tfbb`0_K_lx%r08x%U0N0thNdN!< literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0b0b44e588ba52ef7628208ebbdefa770e256110 GIT binary patch literal 733 zcmchT&q~8U5Qis~URA`CH=!3jY#zW<2oVCI4fPKwVp-R1x;5PmlZj0b#EW;I!jrG2 z_z3Pw)lg3!?830aZx_Cq@8uP`CBlWljFkl{osE&tH@p6Cf?ERqwopacgdTdZgH;%K!^My96C^fkf zO#<8E$L4oTaJMo+z2%v#G4CFsS(UP11Hj^J0n`ZVQ+~@?&UMBjUCr8$1;NhAQ8XN# TM#K0p4uj)(&>sy_cLm7@6-y8r literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized new file mode 100644 index 0000000000000000000000000000000000000000..2ff01fc9d19abc205bb2927323a61a932205a7f8 GIT binary patch literal 115 zcmZ4UmVvdnh#?}sC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDE`Qd3g%N-`630*dkrQj1D5Q;YpeOA1O$R9q`cQuB&4^Yb8ldwY#P-vrHsnHU(O L7?_H(D+(9^Dt9X> literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput.serialized new file mode 100644 index 0000000000000000000000000000000000000000..78ddecc04253cac26a4cf70c69596d048012bfc7 GIT binary patch literal 306 zcmZ4UmVvdnh`}SjC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGWDE`Qd3g%N-`630*dkrQj1D5Q;YpeOA1O$E>CpN|LC__mWhGUhk-30ELOr0pQyUgOUMHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9%jb4yDSlX6lWfkLTyC7H>IC7Jnot`#MzdBs3Rv2#u)P}noCptR)qgX^vTSRO<$ zF);ZsaHqnQc&3yv2>E0smL=-vB<7{-2bX{>xAtLR%>?N}mGn=_N=+`Yt|%yB;7l$` yO$jKKT88K7{=c_Y(X6Sw~2#;bNT_!rHVu0KtTuTQ6as?GxeGa$(#1Nxd?s;2M0k1 zKZCPN7eQ2T=;mZUfP$EuD7tw=NO%&S_j!J~euauw5M?SMS}HD*14Vmmkf|f0S!@)? zAsMi?Th!p8AXIYF==BWJcFO8jVgh+gk!NBvM<%pA=#7+Hxgn%M9kibJ-_I`}eego4 z@M1=m+`~N$JBVw2S0=v_6@et zL0I@zdk5W@1tC-lu759om>^8YigmVCCbf+{UqE))$aMHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9%jb4yDSlX6lWfkLTyC7H>IC7Jnot`#MzdBs3Rv2#u)P}sk;q@c8eqx#L%V ziZd}V`Y^EPLj+401bng*%M$fVOEPoxeKLzntSbtDE|CHW>VX9H9E*w)D~naY6iC6% zB{uuccCcLnniI{ym{`If91SrdCowNw-#;lUH5p_`X%Rzcv=3<>BE}!qDnIl4_s#s> zz{J2%QNX~!zzB4%2Wj>=7p10v!YeT+peVl}wWuUBwHOjgmnXXCfArfd3l1bUNFbFk zM1lOFj}|fdu!zwIMhXanBSs$>G5Wa8SAj<{9 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity.serialized new file mode 100644 index 0000000000000000000000000000000000000000..f0703c6b92f66fc4089155b7d0fbb7bd20b69546 GIT binary patch literal 361 zcmZ4UmVvdnh#@4uC|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9%jb4yDSlX6l6N|SOjlf6?bor_XaQu9hO6LUg~Q;S@ItdhzL?tc7_EaVEA7?^z+ zxKlEV3vv=G{eY&IFbMf%C6*=X=OpH(>j#&BthM%GV9HD>VKDUpIz=DNDf%#{=mVVr z!eFQ91D&GpR9TW*4Ajh$2Q;{lp^kyEqM(F literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredential.serialized new file mode 100644 index 0000000000000000000000000000000000000000..5854d4bed3ca1134d5df858f69820f299d9af0e9 GIT binary patch literal 2288 zcmb_eZA=?w9Dk@lHx^Mw0+|sr2!xS9uLIUqFu~H*LSKLt+7&v(o*vis==JV+?m1|g zqRwn%kp$h0xR~LlGwuWNCB6k_rtZUL%*1TQL{xl9oF8VEpo=-~Z+J|35c%8RRGk*d!D+DKg^4XavCoHzc9BN#R%(@i=7~;==TSDvpUJDD$Qc zH7xL~n@iad*T;#Nhr%zVM~+-vpYJn(Tn{LwTj@Ltv4m_GLpGKm-xxSOgo(*uVwRa0 z!a^U7i6Kmk?e;*89#F&zJb`p1F()d#B>Ff-6|jPV|IR50%ndxnuHm<<;wSb|<@q&Ha5ltoBY<((85x9|_cjMda?{y`3(uRg62g+AYnsLI<`ww(xas z=p}im)8~lR3obnMe$%EiM;T2|Ibqr!FffFgH3^Y%>Pqp|+%;W4F6Y~pHS)TDd%@Jm ziQ{Kp?%@B5p0BO<%nU5`X215t+*oiTI3N1>U}a(6h5`Tl^siOcv6hL^N!!VFM+cu@ zdaUrp52{`zhTgd_No!XWDjBW&YON=G&lnq-oNF+EY!4`an0f%|hIBE|O4k-vw)Jfg z!|Mxc6+S9LtRk%^kezudA!vbOpOBtOB4F1S*cF8&q2&(w$*25VdoJNGG;QanZxU*T ztFygLGleufI&M(u`+ibd`*xSnmRiY}WgjJb-|7w*0|nm-o9^~Lw}4ekn!|NO@EEBk8C9^QFn z=IN3NwuHC?G7dS-4#P%c@41D_@Bgmtty+jT7a!_+cX;O}iN`XS6 zQ79!&BO#$siB6*zN)3%hD402sh)`VdGR5S5|Ns8?N>32+1WdRhr+ZvjPHtY%WtMlv zlJ2prFDwl7JTp~M9~T^*a!a4|P20*&uplYe9COg3_9*kR!s6(PwHn$!-M6u$LD&Gz znnUO_B%b`jlW#ncXjNrAk$92_ka=+fq9~~2aaW*+&|oamRZ4ucY?5XuzpF6d3?Wq^ z{SWgQ35plE45GKPAj(c}*UyH!uMda@p;?HS$~=NLn<#K!sJHae^jck$dC&j~8~{27 zI*$7vV{gUg)MoE4&b)T+-E6z>UD4Cf{^jHO)xGo)Q^V?NSUu_5cAAN)t)sKS*27pB zLgNrdnk%!ke3c}IWXEV_&PU`j)#kEPt}OGN^GR);`CLl1$WaW4tWw*T0XKdnZ&N2n s(x`4kW`z*;J+mN%$0`&4Cw^M|7`|w`bAKqWKoRPdQk0kPt!Ie^pQ1YZK>z>% literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions.serialized new file mode 100644 index 0000000000000000000000000000000000000000..40415ad5dfe779d59650f4b9421c6e5c25e34b24 GIT binary patch literal 1833 zcmbtVT}TvB6uvXAziGMsP-xLoJ@imB4^dePl|R_#f|A=0yBOSEuj|z8%=O+g?QD<~ z7(@>hRP-X@gOHHD2ub;1Jw)`75lU8&v~T&6FTF_7&%I-sg+)UHGsDc>d(L;h^PO)7 zKcIZhP_xZa8mG*#QXLGZNycWUG)|HZGa##FNJ5_2flf=q)X-X-glQz3NVblVc4C2n z&BLV2Asm`17`DYHpVq`?ul3ESs33yMv1!_wpG!HQ^2kYi8tV=irXDdkR7X&8vQw-h zR*C@H84-B&-|*=3cyxh9o*o`u;L&TdK)8reLR=sgmk0nweFixo%9FJuu`HosAyS=b zh}U6@Iv{fd7!9`rS~*vNiLI303X(YStq_bfu^j-kdhWA)*6SVSg%k_Q9ZuL$!iorp710yDA?>w5#D%wXU|m?9b}!xpDD1JRiki@M)RWb*@% zrK0bRKDk&zhfxt|j)xuos`4~6etvl0)+c?sij+9YPe@q-QscEQb(p*leq1|SP!!Fn z2zeZa_Jr>4nht*IUe|bO$90I!Zn`;k#s0jxv8EmW&KqDysG&UU~GX-14;jbZJPvJV{GdO--Vib`qPNHV3i2%a literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialType.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.api.PublicKeyCredentialType.serialized new file mode 100644 index 0000000000000000000000000000000000000000..efc9d8e3ee6ffdf41e7ef918aa0b43897ef12e89 GIT binary patch literal 132 zcmZ4UmVvdnh`}|#C|$3(peQphJ*_A)H?=&!C|j>MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW7yVlX5bXy;Ccli&9fk^GY%kb3!T$QWNX`JM5CZo6p3+=)=HTmY7qTTEZaYla*MO csGpOVm#!aN0MHMz7Xv!qh5JT(b~6H7}n^7Il5 zGW9}>Q;Whj-tF_ctg;o!i;xBrT1SyKrgY4F_E{(0Uy9g~PlVn<_olVl2iA_8d zi#HE?5kye%EcIAH5Km$cB1ruM6i+?q$%Dlo;G3-LwgtB|kV*3L-uJ%u%{NP5p;-zT z4aBr5L&5y%DM2c9J`l5}q;4dbO3Zoc=$l09x^L>0`ii+kvA{R4P$#G3dZ~wB7P^LW zE5C0Wkg=gvVb8oKsgTF<`?kk1E1ArtGh#aNKr}&$?f6lZ4Tw(*4wM!ds5JhI|mEU6o*LaKpiC~ z1W7b{ytsP!;R<=&1eqdaCA&%E5CAgsS-oOWzM=4LAZTh8ty*G^vr5QmK@eY2PphAX z5eYAYSEm#Kr<;`9v8hdpb529^N`uUf5@q{EvK5hO?0Z_D$%o9zXqhI%0_s&aE|_+&5?qwEcDDOy=V-68gFHt$V#?cj=P>kXottT<^0pYx{mI94y@Fzpp0Nk34vH VFZg+M&vNF`tF;%eKkD(i{{Z(Hr?&tA literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken.serialized new file mode 100644 index 0000000000000000000000000000000000000000..36ae5f437c29b8ca554c8e197a1bc36d1dfb1d05 GIT binary patch literal 4101 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 b{4W_ANjhg0a&}v%E1)O|qh^HZe Spring Security Authorization Tag Library - 6.5 + 7.0 security http://www.springframework.org/security/tags From cb0fdef2363bf997671f7644f0034515936ec30a Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 17:50:24 -0500 Subject: [PATCH 151/504] Remove MediaType.APPLICATION_JSON_UTF Closes gh-17050 --- ...ultOAuth2TokenRequestHeadersConverter.java | 6 +-- ...orizationCodeTokenResponseClientTests.java | 3 +- ...ntCredentialsTokenResponseClientTests.java | 3 +- ...aultJwtBearerTokenResponseClientTests.java | 3 +- ...faultPasswordTokenResponseClientTests.java | 3 +- ...tRefreshTokenTokenResponseClientTests.java | 3 +- ...earerGrantRequestEntityConverterTests.java | 3 +- ...nCodeGrantRequestEntityConverterTests.java | 5 ++- ...tialsGrantRequestEntityConverterTests.java | 5 ++- ...swordGrantRequestEntityConverterTests.java | 3 +- ...TokenGrantRequestEntityConverterTests.java | 3 +- .../security/http/MediaTypes.java | 39 +++++++++++++++++++ 12 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 web/src/main/java/org/springframework/security/http/MediaTypes.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java index 92d5d5e1ec..c7bb26f91f 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java @@ -24,6 +24,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -41,9 +42,6 @@ import org.springframework.security.oauth2.core.ClientAuthenticationMethod; public final class DefaultOAuth2TokenRequestHeadersConverter implements Converter { - private static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON, - StandardCharsets.UTF_8); - private static final MediaType APPLICATION_FORM_URLENCODED_UTF8 = new MediaType( MediaType.APPLICATION_FORM_URLENCODED, StandardCharsets.UTF_8); @@ -101,7 +99,7 @@ public final class DefaultOAuth2TokenRequestHeadersConverter DefaultOAuth2TokenRequestHeadersConverter withCharsetUtf8() { DefaultOAuth2TokenRequestHeadersConverter converter = new DefaultOAuth2TokenRequestHeadersConverter<>(); - converter.accept = List.of(APPLICATION_JSON_UTF8); + converter.accept = List.of(MediaTypes.APPLICATION_JSON_UTF8); converter.contentType = APPLICATION_FORM_URLENCODED_UTF8; return converter; } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java index 4aed182e02..e285c61ff6 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java @@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -118,7 +119,7 @@ public class DefaultAuthorizationCodeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java index cc8a62f8aa..d175bcf22b 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java @@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -121,7 +122,7 @@ public class DefaultClientCredentialsTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java index 555d4bbf66..a00a9b0090 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -115,7 +116,7 @@ public class DefaultJwtBearerTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java index 5c0233efc9..a33b234e64 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java @@ -33,6 +33,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -115,7 +116,7 @@ public class DefaultPasswordTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java index d020ce8047..61c4f2d2de 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -117,7 +118,7 @@ public class DefaultRefreshTokenTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); assertThat(recordedRequest.getHeader(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java index c284d2d179..88d06285b2 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java @@ -25,6 +25,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -134,7 +135,7 @@ public class JwtBearerGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.valueOf(MediaType.APPLICATION_JSON_UTF8_VALUE)); + assertThat(headers.getAccept()).contains(MediaType.valueOf(MediaTypes.APPLICATION_JSON_UTF8_VALUE)); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java index 9c4fc4d88f..ac824a681d 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java @@ -28,6 +28,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -138,7 +139,7 @@ public class OAuth2AuthorizationCodeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0JTNE"); @@ -177,7 +178,7 @@ public class OAuth2AuthorizationCodeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).isNull(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java index f988edcd3c..af25ccb9f1 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java @@ -30,6 +30,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -123,7 +124,7 @@ public class OAuth2ClientCredentialsGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); @@ -152,7 +153,7 @@ public class OAuth2ClientCredentialsGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); String urlEncodedClientCredential = URLEncoder.encode(clientCredentialWithAnsiKeyboardSpecialCharacters, diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java index d884559f73..5a6a8811e8 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java @@ -25,6 +25,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -118,7 +119,7 @@ public class OAuth2PasswordGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java index 1278e92e47..fee0e2b02c 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java @@ -27,6 +27,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; +import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -130,7 +131,7 @@ public class OAuth2RefreshTokenGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/web/src/main/java/org/springframework/security/http/MediaTypes.java b/web/src/main/java/org/springframework/security/http/MediaTypes.java new file mode 100644 index 0000000000..96b6c2d989 --- /dev/null +++ b/web/src/main/java/org/springframework/security/http/MediaTypes.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.http; + +import java.nio.charset.StandardCharsets; + +import org.springframework.http.MediaType; + +/** + * This is a placeholder to allow an incremental update to Spring Framework 7.0. + * + * @deprecated For removal + */ +@Deprecated(since = "7.0.0", forRemoval = true) +public final class MediaTypes { + + public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON, + StandardCharsets.UTF_8); + + public static final String APPLICATION_JSON_UTF8_VALUE = APPLICATION_JSON_UTF8.toString(); + + private MediaTypes() { + } + +} From 222faae1cb5e7f5bbea7eeb8c517e7159dedf189 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 2 May 2025 17:31:17 -0500 Subject: [PATCH 152/504] Add junit-jupiter-engine This fixes some of the compatability problems that can happen with newer versions of junit --- config/spring-security-config.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/config/spring-security-config.gradle b/config/spring-security-config.gradle index 90e7b88312..83f91c9bf0 100644 --- a/config/spring-security-config.gradle +++ b/config/spring-security-config.gradle @@ -127,6 +127,7 @@ dependencies { testRuntimeOnly 'org.hsqldb:hsqldb' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' } def rncToXsd = tasks.named('rncToXsd', RncToXsd) From 38a9aa1da999836d7f384eccc59afdee6042ceb9 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 10:48:32 -0500 Subject: [PATCH 153/504] Remove Deprecated PathMatchConfigurer usage Closes gh-17052 --- .../web/builders/WebSecurityTests.java | 57 ---------- .../configurers/AuthorizeRequestsTests.java | 103 ------------------ .../HttpSecurityRequestMatchersTests.java | 61 ----------- .../HttpSecuritySecurityMatchersTests.java | 74 ------------- .../UrlAuthorizationConfigurerTests.java | 58 ---------- .../config/http/InterceptUrlConfigTests.java | 6 - .../web/AuthorizeHttpRequestsDslTests.kt | 28 ----- .../web/AuthorizeRequestsDslTests.kt | 28 ----- .../InterceptUrlConfigTests-MvcMatchers.xml | 2 +- ...gTests-MvcMatchersAuthorizationManager.xml | 2 +- ...tUrlConfigTests-MvcMatchersServletPath.xml | 2 +- ...atchersServletPathAuthorizationManager.xml | 2 +- 12 files changed, 4 insertions(+), 419 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java index 3219676502..a8d18adf4a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java @@ -47,8 +47,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; @@ -84,26 +82,6 @@ public class WebSecurityTests { } } - @Test - public void ignoringMvcMatcher() throws Exception { - loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setRequestURI("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setRequestURI("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setRequestURI("/other"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - @Test public void requestRejectedHandlerInvoked() throws ServletException, IOException { loadConfig(DefaultConfig.class); @@ -132,30 +110,6 @@ public class WebSecurityTests { assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); } - @Test - public void ignoringMvcMatcherServletPath() throws Exception { - loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/other"); - this.request.setRequestURI("/other/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - public void loadConfig(Class... configs) { this.context = new AnnotationConfigWebApplicationContext(); this.context.register(configs); @@ -246,17 +200,6 @@ public class WebSecurityTests { } - @Configuration - static class LegacyMvcMatchingConfig implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(true); - configurer.setUseTrailingSlashMatch(true); - } - - } - @Configuration @EnableWebSecurity static class RequestRejectedHandlerConfig { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java index 65d7c13bea..4bf3d4ef78 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java @@ -48,8 +48,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; @@ -160,67 +158,6 @@ public class AuthorizeRequestsTests { assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); } - @Test - public void mvcMatcher() throws Exception { - loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setRequestURI("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - @Test - public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception { - loadConfig(MvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setRequestURI("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - @Test - public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception { - loadConfig(MvcMatcherServletPathInLambdaConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/foo"); - this.request.setRequestURI("/foo/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/"); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - } - @Test public void mvcMatcherPathVariables() throws Exception { loadConfig(MvcMatcherPathVariablesConfig.class); @@ -245,35 +182,6 @@ public class AuthorizeRequestsTests { assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); } - @Test - public void mvcMatcherServletPath() throws Exception { - loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/foo"); - this.request.setRequestURI("/foo/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/"); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - } - public void loadConfig(Class... configs) { this.context = new AnnotationConfigWebApplicationContext(); this.context.register(configs); @@ -639,15 +547,4 @@ public class AuthorizeRequestsTests { } - @Configuration - static class LegacyMvcMatchingConfig implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(true); - configurer.setUseTrailingSlashMatch(true); - } - - } - } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java index 9fed7f0c4a..52f97c4a3e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java @@ -41,8 +41,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; @@ -80,60 +78,12 @@ public class HttpSecurityRequestMatchersTests { } } - @Test - public void mvcMatcher() throws Exception { - loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - @Test public void mvcMatcherGetFiltersNoUnsupportedMethodExceptionFromDummyRequest() { loadConfig(MvcMatcherConfig.class); assertThat(this.springSecurityFilterChain.getFilters("/path")).isNotEmpty(); } - @Test - public void requestMatchersMvcMatcher() throws Exception { - loadConfig(RequestMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - @Test - public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception { - loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - @Test public void requestMatchersMvcMatcherServletPath() throws Exception { loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class); @@ -491,15 +441,4 @@ public class HttpSecurityRequestMatchersTests { } - @Configuration - static class LegacyMvcMatchingConfig implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(true); - configurer.setUseTrailingSlashMatch(true); - } - - } - } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java index e5c080aefe..3f70043e67 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java @@ -16,8 +16,6 @@ package org.springframework.security.config.annotation.web.configurers; -import java.util.List; - import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -38,19 +36,14 @@ import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.MockServletContext; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; -import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; @@ -88,68 +81,12 @@ public class HttpSecuritySecurityMatchersTests { } } - @Test - public void securityMatcherWhenMvcThenMvcMatcher() throws Exception { - loadConfig(SecurityMatcherMvcConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - @Test public void securityMatcherWhenMvcMatcherAndGetFiltersNoUnsupportedMethodExceptionFromDummyRequest() { loadConfig(SecurityMatcherMvcConfig.class); assertThat(this.springSecurityFilterChain.getFilters("/path")).isNotEmpty(); } - @Test - public void securityMatchersWhenMvcThenMvcMatcher() throws Exception { - loadConfig(SecurityMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - List requestMatchers = this.springSecurityFilterChain.getFilterChains() - .stream() - .map((chain) -> ((DefaultSecurityFilterChain) chain).getRequestMatcher()) - .map((matcher) -> ReflectionTestUtils.getField(matcher, "requestMatchers")) - .map((matchers) -> (List) matchers) - .findFirst() - .get(); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - assertThat(requestMatchers).hasOnlyElementsOfType(MvcRequestMatcher.class); - } - - @Test - public void securityMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception { - loadConfig(SecurityMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - @Test public void securityMatchersMvcMatcherServletPath() throws Exception { loadConfig(SecurityMatchersMvcMatcherServletPathConfig.class); @@ -501,15 +438,4 @@ public class HttpSecuritySecurityMatchersTests { } - @Configuration - static class LegacyMvcMatchingConfig implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(true); - configurer.setUseTrailingSlashMatch(true); - } - - } - } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java index f98c86bbf2..fe93d6bb64 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java @@ -46,8 +46,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; @@ -85,51 +83,6 @@ public class UrlAuthorizationConfigurerTests { } } - @Test - public void mvcMatcher() throws Exception { - loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setRequestURI("/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - @Test - public void mvcMatcherServletPath() throws Exception { - loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path.html"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/spring"); - this.request.setRequestURI("/spring/path/"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - setup(); - this.request.setServletPath("/foo"); - this.request.setRequestURI("/foo/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - setup(); - this.request.setServletPath("/"); - this.request.setRequestURI("/path"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - } - @Test public void anonymousUrlAuthorization() { loadConfig(AnonymousUrlAuthorizationConfig.class); @@ -258,17 +211,6 @@ public class UrlAuthorizationConfigurerTests { } - @Configuration - static class LegacyMvcMatchingConfig implements WebMvcConfigurer { - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(true); - configurer.setUseTrailingSlashMatch(true); - } - - } - @EnableWebSecurity @Configuration @EnableWebMvc diff --git a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java index bdcef2a2a2..f0f983022f 100644 --- a/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/InterceptUrlConfigTests.java @@ -254,8 +254,6 @@ public class InterceptUrlConfigTests { public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception { this.spring.configLocations(this.xml("MvcMatchers")).autowire(); this.mvc.perform(get("/path")).andExpect(status().isUnauthorized()); - this.mvc.perform(get("/path.html")).andExpect(status().isUnauthorized()); - this.mvc.perform(get("/path/")).andExpect(status().isUnauthorized()); } @Test @@ -304,10 +302,6 @@ public class InterceptUrlConfigTests { // @formatter:off this.mvc.perform(get("/spring/path").servletPath("/spring")) .andExpect(status().isUnauthorized()); - this.mvc.perform(get("/spring/path.html").servletPath("/spring")) - .andExpect(status().isUnauthorized()); - this.mvc.perform(get("/spring/path/").servletPath("/spring")) - .andExpect(status().isUnauthorized()); // @formatter:on } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDslTests.kt index dfede958e7..49d40a29c3 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDslTests.kt @@ -150,26 +150,6 @@ class AuthorizeHttpRequestsDslTests { } } - @Test - fun `request when allowed by mvc then responds with OK`() { - this.spring.register(AuthorizeHttpRequestsByMvcConfig::class.java, LegacyMvcMatchingConfig::class.java).autowire() - - this.mockMvc.get("/path") - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/path.html") - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/path/") - .andExpect { - status { isOk() } - } - } - @Configuration @EnableWebSecurity @EnableWebMvc @@ -193,14 +173,6 @@ class AuthorizeHttpRequestsDslTests { } } - @Configuration - open class LegacyMvcMatchingConfig : WebMvcConfigurer { - override fun configurePathMatch(configurer: PathMatchConfigurer) { - configurer.setUseSuffixPatternMatch(true) - configurer.setUseTrailingSlashMatch(true) - } - } - @Test fun `request when secured by mvc path variables then responds based on path variable value`() { this.spring.register(MvcMatcherPathVariablesConfig::class.java).autowire() diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt index be39dbd89d..42eda2bbfc 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt @@ -135,26 +135,6 @@ class AuthorizeRequestsDslTests { } } - @Test - fun `request when allowed by mvc then responds with OK`() { - this.spring.register(AuthorizeRequestsByMvcConfig::class.java, LegacyMvcMatchingConfig::class.java).autowire() - - this.mockMvc.get("/path") - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/path.html") - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/path/") - .andExpect { - status { isOk() } - } - } - @Configuration @EnableWebSecurity @EnableWebMvc @@ -179,14 +159,6 @@ class AuthorizeRequestsDslTests { } } - @Configuration - open class LegacyMvcMatchingConfig : WebMvcConfigurer { - override fun configurePathMatch(configurer: PathMatchConfigurer) { - configurer.setUseSuffixPatternMatch(true) - configurer.setUseTrailingSlashMatch(true) - } - } - @Test fun `request when secured by mvc path variables then responds based on path variable value`() { this.spring.register(MvcMatcherPathVariablesConfig::class.java).autowire() diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchers.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchers.xml index f5eeb472ab..44fc3c7dcd 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchers.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchers.xml @@ -33,7 +33,7 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml index 9edc7c8efa..f63955adef 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersAuthorizationManager.xml @@ -33,7 +33,7 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPath.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPath.xml index 74dabfbd67..749fc6526a 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPath.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPath.xml @@ -33,7 +33,7 @@ - + diff --git a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml index c8a4cc42e9..9b6e686e7b 100644 --- a/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml +++ b/config/src/test/resources/org/springframework/security/config/http/InterceptUrlConfigTests-MvcMatchersServletPathAuthorizationManager.xml @@ -33,7 +33,7 @@ - + From 11105a5c510876f170a43a2285b6a14a3753e6a0 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 10:58:48 -0500 Subject: [PATCH 154/504] UriComponentsBuilder.fromHttpUrl->fromUriString The fromHttpUrl method is deprecated and replaced with fromUriString Closes gh- --- .../web/configurers/saml2/Saml2LoginConfigurerTests.java | 4 ++-- .../client/web/OAuth2LoginAuthenticationFilterTests.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java index 6d874a583d..4d262c91d5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java @@ -253,7 +253,7 @@ public class Saml2LoginConfigurerTests { public void authenticationRequestWhenAuthenticationRequestResolverBeanThenUses() throws Exception { this.spring.register(CustomAuthenticationRequestResolverBean.class).autowire(); MvcResult result = this.mvc.perform(get("/saml2/authenticate/registration-id")).andReturn(); - UriComponents components = UriComponentsBuilder.fromHttpUrl(result.getResponse().getRedirectedUrl()).build(); + UriComponents components = UriComponentsBuilder.fromUriString(result.getResponse().getRedirectedUrl()).build(); String samlRequest = components.getQueryParams().getFirst("SAMLRequest"); String decoded = URLDecoder.decode(samlRequest, "UTF-8"); String inflated = Saml2Utils.samlInflate(Saml2Utils.samlDecode(decoded)); @@ -264,7 +264,7 @@ public class Saml2LoginConfigurerTests { public void authenticationRequestWhenAuthenticationRequestResolverDslThenUses() throws Exception { this.spring.register(CustomAuthenticationRequestResolverDsl.class).autowire(); MvcResult result = this.mvc.perform(get("/saml2/authenticate/registration-id")).andReturn(); - UriComponents components = UriComponentsBuilder.fromHttpUrl(result.getResponse().getRedirectedUrl()).build(); + UriComponents components = UriComponentsBuilder.fromUriString(result.getResponse().getRedirectedUrl()).build(); String samlRequest = components.getQueryParams().getFirst("SAMLRequest"); String decoded = URLDecoder.decode(samlRequest, "UTF-8"); String inflated = Saml2Utils.samlInflate(Saml2Utils.samlDecode(decoded)); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java index bd813ba9e1..3dee3c0cc0 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java @@ -475,7 +475,7 @@ public class OAuth2LoginAuthenticationFilterTests { } private String expandRedirectUri(HttpServletRequest request, ClientRegistration clientRegistration) { - String baseUrl = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request)) + String baseUrl = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)) .replaceQuery(null) .replacePath(request.getContextPath()) .build() From b467c47ed5c1784a6535b7b97635cbfd2c3b0aad Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:06:26 -0500 Subject: [PATCH 155/504] ClientRequest.method->create ClientRequest.method was deprecated in favor of the create method Closes gh-17054 --- .../security/htmlunit/server/HtmlUnitWebTestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java b/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java index bd48fdf85a..29ebaecd42 100644 --- a/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java +++ b/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java @@ -161,7 +161,7 @@ final class HtmlUnitWebTestClient { redirectUrl = scheme + "://" + host + location.toASCIIString(); } // @formatter:off - ClientRequest redirect = ClientRequest.method(HttpMethod.GET, URI.create(redirectUrl)) + ClientRequest redirect = ClientRequest.create(HttpMethod.GET, URI.create(redirectUrl)) .headers((headers) -> headers.addAll(request.headers())) .cookies((cookies) -> cookies.addAll(request.cookies())) .attributes((attributes) -> attributes.putAll(request.attributes())) From 3976e7d456438a352d1d7e8db13f369f3eefecff Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:08:26 -0500 Subject: [PATCH 156/504] BodyInserters.fromObject -> fromProducer Closes gh-17055 --- .../security/htmlunit/server/HtmlUnitWebTestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java b/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java index 29ebaecd42..6389ea83ae 100644 --- a/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java +++ b/config/src/test/java/org/springframework/security/htmlunit/server/HtmlUnitWebTestClient.java @@ -85,7 +85,7 @@ final class HtmlUnitWebTestClient { } return request; } - return request.body(BodyInserters.fromObject(requestBody)); + return request.body(BodyInserters.fromProducer(requestBody, String.class)); } private MultiValueMap formData(List params) { From 5704582c521ba8aa9861740eedde45db762eaa26 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:41:01 -0500 Subject: [PATCH 157/504] ResponseErrorHandler.handleError(URI, HttpMethod,ClientHttpResponse) Closes gh-17056 --- .../http/OAuth2ErrorResponseErrorHandler.java | 6 ++++-- .../OAuth2ErrorResponseErrorHandlerTests.java | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandler.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandler.java index 0b7c058757..cb692846c5 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandler.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandler.java @@ -17,10 +17,12 @@ package org.springframework.security.oauth2.client.http; import java.io.IOException; +import java.net.URI; import com.nimbusds.oauth2.sdk.token.BearerTokenError; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; @@ -53,9 +55,9 @@ public class OAuth2ErrorResponseErrorHandler implements ResponseErrorHandler { } @Override - public void handleError(ClientHttpResponse response) throws IOException { + public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException { if (HttpStatus.BAD_REQUEST.value() != response.getStatusCode().value()) { - this.defaultErrorHandler.handleError(response); + this.defaultErrorHandler.handleError(url, method, response); } // A Bearer Token Error may be in the WWW-Authenticate response header // See https://tools.ietf.org/html/rfc6750#section-3 diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandlerTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandlerTests.java index 602273c52e..b2636c4024 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandlerTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/http/OAuth2ErrorResponseErrorHandlerTests.java @@ -17,10 +17,12 @@ package org.springframework.security.oauth2.client.http; import java.io.IOException; +import java.net.URI; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; @@ -45,6 +47,10 @@ public class OAuth2ErrorResponseErrorHandlerTests { private OAuth2ErrorResponseErrorHandler errorHandler = new OAuth2ErrorResponseErrorHandler(); + private URI anyURi = URI.create("/any"); + + private HttpMethod anyMethod = HttpMethod.GET; + @Test public void handleErrorWhenErrorResponseBodyThenHandled() { // @formatter:off @@ -55,7 +61,7 @@ public class OAuth2ErrorResponseErrorHandlerTests { // @formatter:on MockClientHttpResponse response = new MockClientHttpResponse(errorResponse.getBytes(), HttpStatus.BAD_REQUEST); assertThatExceptionOfType(OAuth2AuthorizationException.class) - .isThrownBy(() -> this.errorHandler.handleError(response)) + .isThrownBy(() -> this.errorHandler.handleError(this.anyURi, this.anyMethod, response)) .withMessage("[unauthorized_client] The client is not authorized"); } @@ -74,7 +80,7 @@ public class OAuth2ErrorResponseErrorHandlerTests { .willReturn(new OAuth2Error("unauthorized_client", "The client is not authorized", null)); assertThatExceptionOfType(OAuth2AuthorizationException.class) - .isThrownBy(() -> this.errorHandler.handleError(response)) + .isThrownBy(() -> this.errorHandler.handleError(this.anyURi, this.anyMethod, response)) .withMessage("[unauthorized_client] The client is not authorized"); verify(oauth2ErrorConverter).read(eq(OAuth2Error.class), eq(response)); } @@ -85,7 +91,7 @@ public class OAuth2ErrorResponseErrorHandlerTests { MockClientHttpResponse response = new MockClientHttpResponse(new byte[0], HttpStatus.BAD_REQUEST); response.getHeaders().add(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticateHeader); assertThatExceptionOfType(OAuth2AuthorizationException.class) - .isThrownBy(() -> this.errorHandler.handleError(response)) + .isThrownBy(() -> this.errorHandler.handleError(this.anyURi, this.anyMethod, response)) .withMessage("[insufficient_scope] The access token expired"); } @@ -95,7 +101,7 @@ public class OAuth2ErrorResponseErrorHandlerTests { MockClientHttpResponse response = new MockClientHttpResponse(new byte[0], HttpStatus.BAD_REQUEST); response.getHeaders().add(HttpHeaders.WWW_AUTHENTICATE, invalidWwwAuthenticateHeader); assertThatExceptionOfType(OAuth2AuthorizationException.class) - .isThrownBy(() -> this.errorHandler.handleError(response)) + .isThrownBy(() -> this.errorHandler.handleError(this.anyURi, this.anyMethod, response)) .withMessage("[server_error] "); } @@ -103,7 +109,7 @@ public class OAuth2ErrorResponseErrorHandlerTests { public void handleErrorWhenErrorResponseWithInvalidStatusCodeThenHandled() { CustomMockClientHttpResponse response = new CustomMockClientHttpResponse(new byte[0], 596); assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> this.errorHandler.handleError(response)) + .isThrownBy(() -> this.errorHandler.handleError(this.anyURi, this.anyMethod, response)) .withMessage("No matching constant for [596]"); } From 2dbf3a2d181febebccf3f6268da19e85dd28244e Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:41:34 -0500 Subject: [PATCH 158/504] WebClient.exchange->exchangeToMono Closes gh-17057 --- .../NimbusReactiveOpaqueTokenIntrospector.java | 10 ++++------ .../NimbusReactiveOpaqueTokenIntrospectorTests.java | 13 +++++++++++-- .../SpringReactiveOpaqueTokenIntrospectorTests.java | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java index b7debd105c..6593248360 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospector.java @@ -98,9 +98,8 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke @Override public Mono introspect(String token) { // @formatter:off - return Mono.just(token) - .flatMap(this::makeRequest) - .flatMap(this::adaptToNimbusResponse) + return this.makeRequest(token) + .exchangeToMono(this::adaptToNimbusResponse) .map(this::parseNimbusResponse) .map(this::castToNimbusSuccess) .doOnNext((response) -> validate(token, response)) @@ -109,13 +108,12 @@ public class NimbusReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke // @formatter:on } - private Mono makeRequest(String token) { + private WebClient.RequestHeadersSpec makeRequest(String token) { // @formatter:off return this.webClient.post() .uri(this.introspectionUri) .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) - .body(BodyInserters.fromFormData("token", token)) - .exchange(); + .body(BodyInserters.fromFormData("token", token)); // @formatter:on } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospectorTests.java index 68ff78a2ac..0b8dd246cd 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospectorTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/NimbusReactiveOpaqueTokenIntrospectorTests.java @@ -23,6 +23,7 @@ import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import net.minidev.json.JSONObject; import okhttp3.mockwebserver.Dispatcher; @@ -45,6 +46,7 @@ import org.springframework.web.reactive.function.client.WebClient; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -265,6 +267,7 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests { } private WebClient mockResponse(String response, String mediaType) { + WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class); WebClient real = WebClient.builder().build(); WebClient.RequestBodyUriSpec spec = spy(real.post()); WebClient webClient = spy(WebClient.class); @@ -275,7 +278,13 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests { ClientResponse.Headers headers = mock(ClientResponse.Headers.class); given(headers.contentType()).willReturn(Optional.ofNullable(mediaType).map(MediaType::parseMediaType)); given(clientResponse.headers()).willReturn(headers); - given(spec.exchange()).willReturn(Mono.just(clientResponse)); + given(responseSpec.bodyToMono(ClientResponse.class)).willReturn(Mono.just(clientResponse)); + given(spec.exchangeToMono(any())).willAnswer((invocation) -> { + Object[] args = invocation.getArguments(); + Function> fn = (Function>) args[0]; + return fn.apply(clientResponse); + }); + given(spec.retrieve()).willReturn(responseSpec); return webClient; } @@ -284,7 +293,7 @@ public class NimbusReactiveOpaqueTokenIntrospectorTests { WebClient.RequestBodyUriSpec spec = spy(real.post()); WebClient webClient = spy(WebClient.class); given(webClient.post()).willReturn(spec); - given(spec.exchange()).willThrow(ex); + given(spec.exchangeToMono(any())).willReturn(Mono.error(ex)); return webClient; } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java index da9d22df23..8f05bd1220 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java @@ -345,7 +345,7 @@ public class SpringReactiveOpaqueTokenIntrospectorTests { WebClient.RequestBodyUriSpec spec = spy(real.post()); WebClient webClient = spy(WebClient.class); given(webClient.post()).willReturn(spec); - given(spec.exchange()).willThrow(ex); + given(spec.exchangeToMono(any())).willThrow(ex); return webClient; } From 66319fc3bc3ef0284f51366545fd4670908c0d3d Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:43:06 -0500 Subject: [PATCH 159/504] MockServerHttpRequest.method(String,String)->method(HttpMethod,String) Closes gh-17058 --- .../security/web/server/csrf/CsrfWebFilterTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/test/java/org/springframework/security/web/server/csrf/CsrfWebFilterTests.java b/web/src/test/java/org/springframework/security/web/server/csrf/CsrfWebFilterTests.java index a60c604914..81c6e6deb8 100644 --- a/web/src/test/java/org/springframework/security/web/server/csrf/CsrfWebFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/csrf/CsrfWebFilterTests.java @@ -24,6 +24,7 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import reactor.test.publisher.PublisherProbe; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; @@ -216,7 +217,7 @@ public class CsrfWebFilterTests { // gh-8452 public void matchesRequireCsrfProtectionWhenNonStandardHTTPMethodIsUsed() { MockServerWebExchange nonStandardHttpExchange = MockServerWebExchange - .from(MockServerHttpRequest.method("non-standard-http-method", "/")); + .from(MockServerHttpRequest.method(HttpMethod.valueOf("non-standard-http-method"), "/")); ServerWebExchangeMatcher serverWebExchangeMatcher = CsrfWebFilter.DEFAULT_CSRF_MATCHER; assertThat(serverWebExchangeMatcher.matches(nonStandardHttpExchange).map(MatchResult::isMatch).block()) .isTrue(); From 607705347c24df3412ce44b1c66acb8d7b5518ce Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:43:22 -0500 Subject: [PATCH 160/504] MediaType.sortBySpecificityAndQuality->sortBySpecificity Closes gh-17059 --- .../server/util/matcher/MediaTypeServerWebExchangeMatcher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java index eb6e5a315d..22c661e96b 100644 --- a/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java +++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java @@ -30,6 +30,7 @@ import org.springframework.core.log.LogMessage; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.util.Assert; +import org.springframework.util.MimeTypeUtils; import org.springframework.web.accept.ContentNegotiationStrategy; import org.springframework.web.server.NotAcceptableStatusException; import org.springframework.web.server.ServerWebExchange; @@ -138,7 +139,7 @@ public class MediaTypeServerWebExchangeMatcher implements ServerWebExchangeMatch private List resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException { try { List mediaTypes = exchange.getRequest().getHeaders().getAccept(); - MediaType.sortBySpecificityAndQuality(mediaTypes); + MimeTypeUtils.sortBySpecificity(mediaTypes); return mediaTypes; } catch (InvalidMediaTypeException ex) { From 0e2d864b09b23e74342df06e9e695202147d2e30 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:44:14 -0500 Subject: [PATCH 161/504] Update Versions --- gradle.properties | 2 +- gradle/libs.versions.toml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index dc0e335d87..19a07278b1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -springBootVersion=3.3.3 +springBootVersion=4.0.0-SNAPSHOT version=7.0.0-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 56d8410fd6..9a4ed86714 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.6" +org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" @@ -31,18 +31,18 @@ commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" io-mockk = "io.mockk:mockk:1.14.2" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M2" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" } io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" } io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.6" -jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:2.1.1" +jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:3.0.0" jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1" -jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.1.0" -jakarta-servlet-jakarta-servlet-api = "jakarta.servlet:jakarta.servlet-api:6.0.0" -jakarta-servlet-jsp-jakarta-servlet-jsp-api = "jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.1" +jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.2.0" +jakarta-servlet-jakarta-servlet-api = "jakarta.servlet:jakarta.servlet-api:6.1.0" +jakarta-servlet-jsp-jakarta-servlet-jsp-api = "jakarta.servlet.jsp:jakarta.servlet.jsp-api:4.0.0" jakarta-servlet-jsp-jstl-jakarta-servlet-jsp-jstl-api = "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.2" jakarta-websocket-jakarta-websocket-api = { module = "jakarta.websocket:jakarta.websocket-api", version.ref = "jakarta-websocket" } jakarta-websocket-jakarta-websocket-client-api = { module = "jakarta.websocket:jakarta.websocket-client-api", version.ref = "jakarta-websocket" } @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.CR1" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.5" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From e5e962ef90f062100cffa07a3c91c52ddba7c667 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:41:59 -0500 Subject: [PATCH 162/504] Jakarta Cookie HttpOnly Serialization The new specification represents Cookie attribute using HttpOnly: "" vs HttpOnly: "true". This updates the test to correspond to the new Servlet specification and is a breaking change related to jakarta updates. --- .../security/web/jackson2/CookieDeserializer.java | 2 +- .../springframework/security/web/jackson2/CookieMixinTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java b/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java index 29a4ca231b..d4123a8188 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java @@ -52,7 +52,7 @@ class CookieDeserializer extends JsonDeserializer { cookie.setVersion(readJsonNode(jsonNode, "version").asInt()); cookie.setPath(readJsonNode(jsonNode, "path").asText()); JsonNode attributes = readJsonNode(jsonNode, "attributes"); - cookie.setHttpOnly(readJsonNode(attributes, "HttpOnly").asBoolean()); + cookie.setHttpOnly(readJsonNode(attributes, "HttpOnly") != null); return cookie; } diff --git a/web/src/test/java/org/springframework/security/web/jackson2/CookieMixinTests.java b/web/src/test/java/org/springframework/security/web/jackson2/CookieMixinTests.java index 0e8cdfd032..3b14b222ee 100644 --- a/web/src/test/java/org/springframework/security/web/jackson2/CookieMixinTests.java +++ b/web/src/test/java/org/springframework/security/web/jackson2/CookieMixinTests.java @@ -52,7 +52,7 @@ public class CookieMixinTests extends AbstractMixinTests { " \"@class\": \"jakarta.servlet.http.Cookie\"," + " \"name\": \"demo\"," + " \"value\": \"cookie1\"," + - " \"attributes\":{\"@class\":\"java.util.Collections$UnmodifiableMap\", \"HttpOnly\": \"true\"}," + + " \"attributes\":{\"@class\":\"java.util.Collections$UnmodifiableMap\", \"HttpOnly\": \"\"}," + " \"comment\": null," + " \"maxAge\": -1," + " \"path\": null," + From b453840c0a0296bacb5d8182a64bd6a2c16adda6 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:10:28 -0500 Subject: [PATCH 163/504] HttpHeaders no longer a MultiValueMap Closes gh-17060 --- .../config/web/server/CorsSpecTests.java | 9 ++++--- .../config/web/server/HeaderSpecTests.java | 13 +++++----- .../web/server/OidcLogoutSpecTests.java | 2 +- .../web/server/ServerHttpsRedirectDslTests.kt | 4 ++-- ...enServerAuthenticationEntryPointTests.java | 2 +- .../security/web/FilterInvocation.java | 2 +- .../StrictServerWebExchangeFirewall.java | 24 ++++++++----------- .../header/StaticServerHttpHeadersWriter.java | 4 ++-- .../StrictServerWebExchangeFirewallTests.java | 2 +- ...heControlServerHttpHeadersWriterTests.java | 8 +++---- ...ityPolicyServerHttpHeadersWriterTests.java | 10 ++++---- ...peOptionsServerHttpHeadersWriterTests.java | 4 ++-- ...derPolicyServerHttpHeadersWriterTests.java | 6 ++--- ...nerPolicyServerHttpHeadersWriterTests.java | 6 ++--- ...rcePolicyServerHttpHeadersWriterTests.java | 6 ++--- ...urePolicyServerHttpHeadersWriterTests.java | 6 ++--- ...onsPolicyServerHttpHeadersWriterTests.java | 6 ++--- ...rerPolicyServerHttpHeadersWriterTests.java | 6 ++--- .../StaticServerHttpHeadersWriterTests.java | 2 +- ...tSecurityServerHttpHeadersWriterTests.java | 24 +++++++++---------- ...peOptionsServerHttpHeadersWriterTests.java | 4 ++-- ...meOptionsServerHttpHeadersWriterTests.java | 8 +++---- ...rotectionServerHttpHeadersWriterTests.java | 10 ++++---- 23 files changed, 81 insertions(+), 87 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java index 63646400ef..3ae317d751 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java @@ -18,8 +18,6 @@ package org.springframework.security.config.web.server; import java.util.Arrays; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; import org.junit.jupiter.api.BeforeEach; @@ -114,12 +112,13 @@ public class CorsSpecTests { .exchange() .returnResult(String.class); // @formatter:on - Map> responseHeaders = response.getResponseHeaders(); + HttpHeaders responseHeaders = response.getResponseHeaders(); if (!this.expectedHeaders.isEmpty()) { - assertThat(responseHeaders).describedAs(response.toString()).containsAllEntriesOf(this.expectedHeaders); + this.expectedHeaders.forEach( + (headerName, headerValues) -> assertThat(responseHeaders.get(headerName)).isEqualTo(headerValues)); } if (!this.headerNamesNotPresent.isEmpty()) { - assertThat(responseHeaders.keySet()).doesNotContainAnyElementsOf(this.headerNamesNotPresent); + assertThat(responseHeaders.headerNames()).doesNotContainAnyElementsOf(this.headerNamesNotPresent); } } diff --git a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java index 50dbe184b2..486cf40798 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java @@ -18,8 +18,6 @@ package org.springframework.security.config.web.server; import java.time.Duration; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; import org.junit.jupiter.api.BeforeEach; @@ -80,14 +78,14 @@ public class HeaderSpecTests { @Test public void headersWhenDisableThenNoSecurityHeaders() { - new HashSet<>(this.expectedHeaders.keySet()).forEach(this::expectHeaderNamesNotPresent); + new HashSet<>(this.expectedHeaders.headerNames()).forEach(this::expectHeaderNamesNotPresent); this.http.headers().disable(); assertHeaders(); } @Test public void headersWhenDisableInLambdaThenNoSecurityHeaders() { - new HashSet<>(this.expectedHeaders.keySet()).forEach(this::expectHeaderNamesNotPresent); + new HashSet<>(this.expectedHeaders.headerNames()).forEach(this::expectHeaderNamesNotPresent); this.http.headers((headers) -> headers.disable()); assertHeaders(); } @@ -515,12 +513,13 @@ public class HeaderSpecTests { .uri("https://example.com/") .exchange() .returnResult(String.class); - Map> responseHeaders = response.getResponseHeaders(); + HttpHeaders responseHeaders = response.getResponseHeaders(); if (!this.expectedHeaders.isEmpty()) { - assertThat(responseHeaders).describedAs(response.toString()).containsAllEntriesOf(this.expectedHeaders); + this.expectedHeaders.forEach( + (headerName, headerValues) -> assertThat(responseHeaders.get(headerName)).isEqualTo(headerValues)); } if (!this.headerNamesNotPresent.isEmpty()) { - assertThat(responseHeaders.keySet()).doesNotContainAnyElementsOf(this.headerNamesNotPresent); + assertThat(responseHeaders.headerNames()).doesNotContainAnyElementsOf(this.headerNamesNotPresent); } } diff --git a/config/src/test/java/org/springframework/security/config/web/server/OidcLogoutSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OidcLogoutSpecTests.java index ebff5d102b..5c5a9cb44b 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OidcLogoutSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OidcLogoutSpecTests.java @@ -945,7 +945,7 @@ public class OidcLogoutSpecTests { private MockResponse toMockResponse(FluxExchangeResult result) { MockResponse response = new MockResponse(); response.setResponseCode(result.getStatus().value()); - for (String name : result.getResponseHeaders().keySet()) { + for (String name : result.getResponseHeaders().headerNames()) { response.addHeader(name, result.getResponseHeaders().getFirst(name)); } String body = result.getResponseBody().blockFirst(); diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpsRedirectDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpsRedirectDslTests.kt index 3d302582dd..8588447cb0 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpsRedirectDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpsRedirectDslTests.kt @@ -127,7 +127,7 @@ class ServerHttpsRedirectDslTests { return http { redirectToHttps { httpsRedirectWhen { - it.request.headers.containsKey("X-Requires-Https") + it.request.headers.headerNames().contains("X-Requires-Https") } } } @@ -165,7 +165,7 @@ class ServerHttpsRedirectDslTests { redirectToHttps { httpsRedirectWhen(PathPatternParserServerWebExchangeMatcher("/secure")) httpsRedirectWhen { - it.request.headers.containsKey("X-Requires-Https") + it.request.headers.headerNames().contains("X-Requires-Https") } } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/BearerTokenServerAuthenticationEntryPointTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/BearerTokenServerAuthenticationEntryPointTests.java index c8df65119c..8f25f4e710 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/BearerTokenServerAuthenticationEntryPointTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/BearerTokenServerAuthenticationEntryPointTests.java @@ -91,7 +91,7 @@ public class BearerTokenServerAuthenticationEntryPointTests { @Test public void commenceWhenNoSubscriberThenNothingHappens() { this.entryPoint.commence(this.exchange, new BadCredentialsException("")); - assertThat(getResponse().getHeaders()).isEmpty(); + assertThat(getResponse().getHeaders().headerNames()).isEmpty(); assertThat(getResponse().getStatusCode()).isNull(); } diff --git a/web/src/main/java/org/springframework/security/web/FilterInvocation.java b/web/src/main/java/org/springframework/security/web/FilterInvocation.java index f9f86476c8..c5fdf8e2d8 100644 --- a/web/src/main/java/org/springframework/security/web/FilterInvocation.java +++ b/web/src/main/java/org/springframework/security/web/FilterInvocation.java @@ -267,7 +267,7 @@ public class FilterInvocation { @Override public Enumeration getHeaderNames() { - return Collections.enumeration(this.headers.keySet()); + return Collections.enumeration(this.headers.headerNames()); } @Override diff --git a/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java b/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java index 72871f2b45..8c6054cd73 100644 --- a/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java +++ b/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java @@ -135,8 +135,8 @@ public class StrictServerWebExchangeFirewall implements ServerWebExchangeFirewal private static final Pattern ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN = Pattern .compile("[\\p{IsAssigned}&&[^\\p{IsControl}]]*"); - private static final Predicate ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE = ( - s) -> ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN.matcher(s).matches(); + private static final Predicate ASSIGNED_AND_NOT_ISO_CONTROL_PREDICATE = (s) -> s == null + || ASSIGNED_AND_NOT_ISO_CONTROL_PATTERN.matcher(s).matches(); private static final Pattern HEADER_VALUE_PATTERN = Pattern.compile("[\\p{IsAssigned}&&[[^\\p{IsControl}]||\\t]]*"); @@ -198,13 +198,11 @@ public class StrictServerWebExchangeFirewall implements ServerWebExchangeFirewal exchange.getResponse().beforeCommit(() -> Mono.fromRunnable(() -> { ServerHttpResponse response = exchange.getResponse(); HttpHeaders headers = response.getHeaders(); - for (Map.Entry> header : headers.entrySet()) { - String headerName = header.getKey(); - List headerValues = header.getValue(); + headers.forEach((headerName, headerValues) -> { for (String headerValue : headerValues) { validateCrlf(headerName, headerValue); } - } + }); })); return new StrictFirewallServerWebExchange(exchange); }); @@ -767,23 +765,21 @@ public class StrictServerWebExchangeFirewall implements ServerWebExchangeFirewal } @Override - public List get(Object key) { - if (key instanceof String headerName) { - validateAllowedHeaderName(headerName); - } - List headerValues = super.get(key); + public List get(String headerName) { + validateAllowedHeaderName(headerName); + List headerValues = super.get(headerName); if (headerValues == null) { return headerValues; } for (String headerValue : headerValues) { - validateAllowedHeaderValue(key, headerValue); + validateAllowedHeaderValue(headerName, headerValue); } return headerValues; } @Override - public Set keySet() { - Set headerNames = super.keySet(); + public Set headerNames() { + Set headerNames = super.headerNames(); for (String headerName : headerNames) { validateAllowedHeaderName(headerName); } diff --git a/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java index fb3d3c4d77..6ea83366a8 100644 --- a/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java +++ b/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java @@ -43,8 +43,8 @@ public class StaticServerHttpHeadersWriter implements ServerHttpHeadersWriter { // Note: We need to ensure that the following algorithm compares headers // case insensitively, which should be true of headers.containsKey(). boolean containsNoHeadersToAdd = true; - for (String headerName : this.headersToAdd.keySet()) { - if (headers.containsKey(headerName)) { + for (String headerName : this.headersToAdd.headerNames()) { + if (headers.containsHeader(headerName)) { containsNoHeadersToAdd = false; break; } diff --git a/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java b/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java index 8f24b0522c..6d81eafe24 100644 --- a/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java +++ b/web/src/test/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewallTests.java @@ -444,7 +444,7 @@ class StrictServerWebExchangeFirewallTests { ServerWebExchange exchange = getFirewalledExchange(); HttpHeaders headers = exchange.getRequest().getHeaders(); assertThatExceptionOfType(ServerExchangeRejectedException.class) - .isThrownBy(() -> headers.keySet().iterator().next()); + .isThrownBy(() -> headers.headerNames().iterator().next()); } @Test diff --git a/web/src/test/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriterTests.java index 822750041a..e9e14518db 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriterTests.java @@ -42,7 +42,7 @@ public class CacheControlServerHttpHeadersWriterTests { @Test public void writeHeadersWhenCacheHeadersThenWritesAllCacheControl() { this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(3); + assertThat(this.headers.headerNames()).hasSize(3); assertThat(this.headers.get(HttpHeaders.CACHE_CONTROL)) .containsOnly(CacheControlServerHttpHeadersWriter.CACHE_CONTRTOL_VALUE); assertThat(this.headers.get(HttpHeaders.EXPIRES)) @@ -63,7 +63,7 @@ public class CacheControlServerHttpHeadersWriterTests { String pragma = "1"; this.headers.set(HttpHeaders.PRAGMA, pragma); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(HttpHeaders.PRAGMA)).containsOnly(pragma); } @@ -72,7 +72,7 @@ public class CacheControlServerHttpHeadersWriterTests { String expires = "1"; this.headers.set(HttpHeaders.EXPIRES, expires); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(HttpHeaders.EXPIRES)).containsOnly(expires); } @@ -81,7 +81,7 @@ public class CacheControlServerHttpHeadersWriterTests { public void writeHeadersWhenNotModifiedThenNoCacheControlHeaders() { this.exchange.getResponse().setStatusCode(HttpStatus.NOT_MODIFIED); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).isEmpty(); + assertThat(this.headers.headerNames()).isEmpty(); } } diff --git a/web/src/test/java/org/springframework/security/web/server/header/ContentSecurityPolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/ContentSecurityPolicyServerHttpHeadersWriterTests.java index 28efe3b190..984f309f41 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/ContentSecurityPolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/ContentSecurityPolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ public class ContentSecurityPolicyServerHttpHeadersWriterTests { public void writeHeadersWhenUsingDefaultsThenDoesNotWrite() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -57,7 +57,7 @@ public class ContentSecurityPolicyServerHttpHeadersWriterTests { this.writer.setPolicyDirectives(DEFAULT_POLICY_DIRECTIVES); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY)) .containsOnly(DEFAULT_POLICY_DIRECTIVES); } @@ -68,7 +68,7 @@ public class ContentSecurityPolicyServerHttpHeadersWriterTests { this.writer.setReportOnly(true); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY_REPORT_ONLY)) .containsOnly(DEFAULT_POLICY_DIRECTIVES); } @@ -78,7 +78,7 @@ public class ContentSecurityPolicyServerHttpHeadersWriterTests { this.writer.setReportOnly(true); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -89,7 +89,7 @@ public class ContentSecurityPolicyServerHttpHeadersWriterTests { .set(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY, headerValue); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY)) .containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/ContentTypeOptionsServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/ContentTypeOptionsServerHttpHeadersWriterTests.java index 4221e36a1e..1258ded69c 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/ContentTypeOptionsServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/ContentTypeOptionsServerHttpHeadersWriterTests.java @@ -41,7 +41,7 @@ class ContentTypeOptionsServerHttpHeadersWriterTests { @Test void writeHeadersWhenNoHeadersThenWriteHeaders() { this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS)) .containsOnly(ContentTypeOptionsServerHttpHeadersWriter.NOSNIFF); } @@ -51,7 +51,7 @@ class ContentTypeOptionsServerHttpHeadersWriterTests { String headerValue = "value"; this.headers.set(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, headerValue); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS)) .containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriterTests.java index c4be94b856..23c3f8695d 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ class CrossOriginEmbedderPolicyServerHttpHeadersWriterTests { void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -59,7 +59,7 @@ class CrossOriginEmbedderPolicyServerHttpHeadersWriterTests { .add(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY, "require-corp"); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY)) .containsOnly("require-corp"); } @@ -69,7 +69,7 @@ class CrossOriginEmbedderPolicyServerHttpHeadersWriterTests { this.writer.setPolicy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY)) .containsOnly("require-corp"); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginOpenerPolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginOpenerPolicyServerHttpHeadersWriterTests.java index 0f5f993377..8e44be6633 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginOpenerPolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginOpenerPolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ class CrossOriginOpenerPolicyServerHttpHeadersWriterTests { void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -59,7 +59,7 @@ class CrossOriginOpenerPolicyServerHttpHeadersWriterTests { .add(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY, "same-origin"); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY)) .containsOnly("same-origin"); } @@ -70,7 +70,7 @@ class CrossOriginOpenerPolicyServerHttpHeadersWriterTests { .setPolicy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY)) .containsOnly("same-origin-allow-popups"); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginResourcePolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginResourcePolicyServerHttpHeadersWriterTests.java index 01b1242f27..bab94892c9 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/CrossOriginResourcePolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/CrossOriginResourcePolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ class CrossOriginResourcePolicyServerHttpHeadersWriterTests { void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -59,7 +59,7 @@ class CrossOriginResourcePolicyServerHttpHeadersWriterTests { .add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY, "same-origin"); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY)) .containsOnly("same-origin"); } @@ -69,7 +69,7 @@ class CrossOriginResourcePolicyServerHttpHeadersWriterTests { this.writer.setPolicy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY)) .containsOnly("same-origin"); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/FeaturePolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/FeaturePolicyServerHttpHeadersWriterTests.java index 8e03858642..bc0d952fb8 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/FeaturePolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/FeaturePolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ public class FeaturePolicyServerHttpHeadersWriterTests { public void writeHeadersWhenUsingDefaultsThenDoesNotWrite() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -57,7 +57,7 @@ public class FeaturePolicyServerHttpHeadersWriterTests { this.writer.setPolicyDirectives(DEFAULT_POLICY_DIRECTIVES); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(FeaturePolicyServerHttpHeadersWriter.FEATURE_POLICY)) .containsOnly(DEFAULT_POLICY_DIRECTIVES); } @@ -69,7 +69,7 @@ public class FeaturePolicyServerHttpHeadersWriterTests { this.exchange.getResponse().getHeaders().set(FeaturePolicyServerHttpHeadersWriter.FEATURE_POLICY, headerValue); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(FeaturePolicyServerHttpHeadersWriter.FEATURE_POLICY)).containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/PermissionsPolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/PermissionsPolicyServerHttpHeadersWriterTests.java index 8c41443839..1a222bdb73 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/PermissionsPolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/PermissionsPolicyServerHttpHeadersWriterTests.java @@ -49,7 +49,7 @@ public class PermissionsPolicyServerHttpHeadersWriterTests { public void writeHeadersWhenUsingDefaultsThenDoesNotWrite() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -57,7 +57,7 @@ public class PermissionsPolicyServerHttpHeadersWriterTests { this.writer.setPolicy(DEFAULT_POLICY_DIRECTIVES); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY)) .containsOnly(DEFAULT_POLICY_DIRECTIVES); } @@ -71,7 +71,7 @@ public class PermissionsPolicyServerHttpHeadersWriterTests { .set(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY, headerValue); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY)).containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/ReferrerPolicyServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/ReferrerPolicyServerHttpHeadersWriterTests.java index 06ca50074a..51b235a6a0 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/ReferrerPolicyServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/ReferrerPolicyServerHttpHeadersWriterTests.java @@ -48,7 +48,7 @@ public class ReferrerPolicyServerHttpHeadersWriterTests { public void writeHeadersWhenUsingDefaultsThenDoesNotWrite() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY)) .containsOnly(ReferrerPolicy.NO_REFERRER.getPolicy()); } @@ -58,7 +58,7 @@ public class ReferrerPolicyServerHttpHeadersWriterTests { this.writer.setPolicy(ReferrerPolicy.SAME_ORIGIN); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY)) .containsOnly(ReferrerPolicy.SAME_ORIGIN.getPolicy()); } @@ -71,7 +71,7 @@ public class ReferrerPolicyServerHttpHeadersWriterTests { .set(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY, headerValue); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY)).containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriterTests.java index ee3734181a..d11c1af9d4 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriterTests.java @@ -102,7 +102,7 @@ public class StaticServerHttpHeadersWriterTests { .header(HttpHeaders.EXPIRES, CacheControlServerHttpHeadersWriter.EXPIRES_VALUE) .build(); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(HttpHeaders.CACHE_CONTROL)).containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriterTests.java index 02ed96d3e7..989106e768 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriterTests.java @@ -17,7 +17,6 @@ package org.springframework.security.web.server.header; import java.time.Duration; -import java.util.Arrays; import org.junit.jupiter.api.Test; @@ -43,9 +42,10 @@ public class StrictTransportSecurityServerHttpHeadersWriterTests { this.exchange = exchange(MockServerHttpRequest.get("https://example.com/")); this.hsts.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); - assertThat(headers).containsEntry(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, - Arrays.asList("max-age=31536000 ; includeSubDomains")); + assertThat(headers.headerNames()).hasSize(1); + assertThat(headers.containsHeaderValue(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, + "max-age=31536000 ; includeSubDomains")) + .isTrue(); } @Test @@ -55,9 +55,9 @@ public class StrictTransportSecurityServerHttpHeadersWriterTests { this.exchange = exchange(MockServerHttpRequest.get("https://example.com/")); this.hsts.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); - assertThat(headers).containsEntry(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, - Arrays.asList("max-age=" + maxAge.getSeconds() + " ; includeSubDomains")); + assertThat(headers.headerNames()).hasSize(1); + assertThat(headers.containsHeaderValue(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, + "max-age=" + maxAge.getSeconds() + " ; includeSubDomains")); } @Test @@ -66,9 +66,9 @@ public class StrictTransportSecurityServerHttpHeadersWriterTests { this.exchange = exchange(MockServerHttpRequest.get("https://example.com/")); this.hsts.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); - assertThat(headers).containsEntry(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, - Arrays.asList("max-age=31536000")); + assertThat(headers.headerNames()).hasSize(1); + assertThat(headers.containsHeaderValue(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, + "max-age=31536000")); } @Test @@ -76,7 +76,7 @@ public class StrictTransportSecurityServerHttpHeadersWriterTests { this.exchange = exchange(MockServerHttpRequest.get("/")); this.hsts.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } @Test @@ -84,7 +84,7 @@ public class StrictTransportSecurityServerHttpHeadersWriterTests { this.exchange = exchange(MockServerHttpRequest.get("http://localhost/")); this.hsts.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).isEmpty(); + assertThat(headers.headerNames()).isEmpty(); } private static MockServerWebExchange exchange(MockServerHttpRequest.BaseBuilder request) { diff --git a/web/src/test/java/org/springframework/security/web/server/header/XContentTypeOptionsServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/XContentTypeOptionsServerHttpHeadersWriterTests.java index 617bf5592d..0ca008d582 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/XContentTypeOptionsServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/XContentTypeOptionsServerHttpHeadersWriterTests.java @@ -42,7 +42,7 @@ public class XContentTypeOptionsServerHttpHeadersWriterTests { @Test public void writeHeadersWhenNoHeadersThenWriteHeadersForXContentTypeOptionsServerHttpHeadersWriter() { this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS)) .containsOnly(XContentTypeOptionsServerHttpHeadersWriter.NOSNIFF); } @@ -52,7 +52,7 @@ public class XContentTypeOptionsServerHttpHeadersWriterTests { String headerValue = "value"; this.headers.set(XContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS, headerValue); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS)) .containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriterTests.java index 98ee2e5300..ceedd456d2 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriterTests.java @@ -45,7 +45,7 @@ public class XFrameOptionsServerHttpHeadersWriterTests { public void writeHeadersWhenUsingDefaultsThenWritesDeny() { this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS)).containsOnly("DENY"); } @@ -54,7 +54,7 @@ public class XFrameOptionsServerHttpHeadersWriterTests { this.writer.setMode(XFrameOptionsServerHttpHeadersWriter.Mode.DENY); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS)).containsOnly("DENY"); } @@ -63,7 +63,7 @@ public class XFrameOptionsServerHttpHeadersWriterTests { this.writer.setMode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS)).containsOnly("SAMEORIGIN"); } @@ -73,7 +73,7 @@ public class XFrameOptionsServerHttpHeadersWriterTests { this.exchange.getResponse().getHeaders().set(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, headerValue); this.writer.writeHttpHeaders(this.exchange); HttpHeaders headers = this.exchange.getResponse().getHeaders(); - assertThat(headers).hasSize(1); + assertThat(headers.headerNames()).hasSize(1); assertThat(headers.get(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS)).containsOnly(headerValue); } diff --git a/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java b/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java index 1b3d882656..e22a308f41 100644 --- a/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriterTests.java @@ -47,7 +47,7 @@ public class XXssProtectionServerHttpHeadersWriterTests { @Test public void writeHeadersWhenNoHeadersThenWriteHeaders() { this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("0"); } @@ -56,7 +56,7 @@ public class XXssProtectionServerHttpHeadersWriterTests { String headerValue = "value"; this.headers.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, headerValue); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly(headerValue); } @@ -64,7 +64,7 @@ public class XXssProtectionServerHttpHeadersWriterTests { void writeHeadersWhenDisabledThenWriteHeaders() { this.writer.setHeaderValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("0"); } @@ -72,7 +72,7 @@ public class XXssProtectionServerHttpHeadersWriterTests { void writeHeadersWhenEnabledThenWriteHeaders() { this.writer.setHeaderValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)).containsOnly("1"); } @@ -80,7 +80,7 @@ public class XXssProtectionServerHttpHeadersWriterTests { void writeHeadersWhenEnabledModeBlockThenWriteHeaders() { this.writer.setHeaderValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK); this.writer.writeHttpHeaders(this.exchange); - assertThat(this.headers).hasSize(1); + assertThat(this.headers.headerNames()).hasSize(1); assertThat(this.headers.get(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION)) .containsOnly("1; mode=block"); } From a80592a7079a06670a11e5c179c188c4771a2917 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 11:43:53 -0500 Subject: [PATCH 164/504] Use commons-logging directly Closes gh-17061 --- .../classpath/CheckClasspathForProhibitedDependencies.java | 3 --- crypto/spring-security-crypto.gradle | 1 - 2 files changed, 4 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java b/buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java index 4738135e90..20036418d6 100644 --- a/buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java +++ b/buildSrc/src/main/java/org/springframework/gradle/classpath/CheckClasspathForProhibitedDependencies.java @@ -81,9 +81,6 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask { if (group.startsWith("javax")) { return true; } - if (group.equals("commons-logging")) { - return true; - } if (group.equals("org.slf4j") && id.getName().equals("jcl-over-slf4j")) { return true; } diff --git a/crypto/spring-security-crypto.gradle b/crypto/spring-security-crypto.gradle index 78a8fd31d0..2b010da16a 100644 --- a/crypto/spring-security-crypto.gradle +++ b/crypto/spring-security-crypto.gradle @@ -2,7 +2,6 @@ apply plugin: 'io.spring.convention.spring-module' dependencies { management platform(project(":spring-security-dependencies")) - optional 'org.springframework:spring-jcl' optional 'org.springframework:spring-core' optional 'org.bouncycastle:bcpkix-jdk18on' From e599a17303b0a4b34400944a56829c9799dd218d Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 13:40:06 -0500 Subject: [PATCH 165/504] Update SNAPSHOT tests Issueh gh-17047 --- .github/workflows/continuous-integration-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index 23cdae4f8c..51d2df3b34 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -39,7 +39,7 @@ jobs: toolchain: 17 with: java-version: ${{ matrix.java-version }} - test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ --stacktrace + test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace secrets: inherit check-samples: name: Check Samples From 866d8d0eab40f251770212eae1e248d6e07c9dd7 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 6 May 2025 13:42:13 -0500 Subject: [PATCH 166/504] Disable samples build Spring Boot doesn't support Framework 7 yet Issue gh-17047 --- .../continuous-integration-workflow.yml | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index 51d2df3b34..f8dd0d5584 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -41,46 +41,23 @@ jobs: java-version: ${{ matrix.java-version }} test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace secrets: inherit - check-samples: - name: Check Samples - runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'spring-projects' }} - steps: - - uses: actions/checkout@v4 - - name: Set up gradle - uses: spring-io/spring-gradle-build-action@v2 - with: - java-version: 17 - distribution: temurin - - name: Check samples project - env: - LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos - SAMPLES_DIR: ../spring-security-samples - run: | - # Extract version from gradle.properties - version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}') - # Extract samplesBranch from gradle.properties - samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}') - ./gradlew publishMavenJavaPublicationToLocalRepository - ./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR" - ./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest deploy-artifacts: name: Deploy Artifacts - needs: [ build, test, check-samples ] + needs: [ build, test] uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1 with: should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }} secrets: inherit deploy-docs: name: Deploy Docs - needs: [ build, test, check-samples ] + needs: [ build, test ] uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1 with: should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }} secrets: inherit deploy-schema: name: Deploy Schema - needs: [ build, test, check-samples ] + needs: [ build, test ] uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1 with: should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }} From 421fcaee12ef287eea9cf01b4ab89825c666cad0 Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Sun, 27 Apr 2025 18:16:17 +0300 Subject: [PATCH 167/504] Add Assertions To WebAuthnConfigurer Signed-off-by: Max Batischev --- .../annotation/web/configurers/WebAuthnConfigurer.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java index 104a0be328..fba5f016fa 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java @@ -46,6 +46,7 @@ import org.springframework.security.web.webauthn.registration.DefaultWebAuthnReg import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsFilter; import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsRepository; import org.springframework.security.web.webauthn.registration.WebAuthnRegistrationFilter; +import org.springframework.util.Assert; /** * Configures WebAuthn for Spring Security applications @@ -75,6 +76,7 @@ public class WebAuthnConfigurer> * @return the {@link WebAuthnConfigurer} for further customization */ public WebAuthnConfigurer rpId(String rpId) { + Assert.hasText(rpId, "rpId be null or empty"); this.rpId = rpId; return this; } @@ -85,6 +87,7 @@ public class WebAuthnConfigurer> * @return the {@link WebAuthnConfigurer} for further customization */ public WebAuthnConfigurer rpName(String rpName) { + Assert.hasText(rpName, "rpName can't be null or empty"); this.rpName = rpName; return this; } @@ -106,6 +109,7 @@ public class WebAuthnConfigurer> * @see #allowedOrigins(String...) */ public WebAuthnConfigurer allowedOrigins(Set allowedOrigins) { + Assert.notNull(allowedOrigins, "allowedOrigins can't be null"); this.allowedOrigins = allowedOrigins; return this; } @@ -129,6 +133,7 @@ public class WebAuthnConfigurer> * @return the {@link WebAuthnConfigurer} for further customization */ public WebAuthnConfigurer messageConverter(HttpMessageConverter converter) { + Assert.notNull(converter, "converter can't be null"); this.converter = converter; return this; } @@ -140,6 +145,7 @@ public class WebAuthnConfigurer> */ public WebAuthnConfigurer creationOptionsRepository( PublicKeyCredentialCreationOptionsRepository creationOptionsRepository) { + Assert.notNull(creationOptionsRepository, "creationOptionsRepository can't be null"); this.creationOptionsRepository = creationOptionsRepository; return this; } From 66e614cb0b3b8dca6018075ac39fb83caca3bb16 Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Sun, 27 Apr 2025 18:19:12 +0300 Subject: [PATCH 168/504] WebAuthnConfigurer Code Cleanup Signed-off-by: Max Batischev --- .../web/configurers/WebAuthnConfigurer.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java index fba5f016fa..de01d55b4e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java @@ -152,9 +152,8 @@ public class WebAuthnConfigurer> @Override public void configure(H http) throws Exception { - UserDetailsService userDetailsService = getSharedOrBean(http, UserDetailsService.class).orElseGet(() -> { - throw new IllegalStateException("Missing UserDetailsService Bean"); - }); + UserDetailsService userDetailsService = getSharedOrBean(http, UserDetailsService.class) + .orElseThrow(() -> new IllegalStateException("Missing UserDetailsService Bean")); PublicKeyCredentialUserEntityRepository userEntities = getSharedOrBean(http, PublicKeyCredentialUserEntityRepository.class) .orElse(userEntityRepository()); @@ -244,12 +243,9 @@ public class WebAuthnConfigurer> PublicKeyCredentialUserEntityRepository userEntities, UserCredentialRepository userCredentials) { Optional webauthnOperationsBean = getBeanOrNull( WebAuthnRelyingPartyOperations.class); - if (webauthnOperationsBean.isPresent()) { - return webauthnOperationsBean.get(); - } - Webauthn4JRelyingPartyOperations result = new Webauthn4JRelyingPartyOperations(userEntities, userCredentials, - PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(), this.allowedOrigins); - return result; + return webauthnOperationsBean.orElseGet(() -> new Webauthn4JRelyingPartyOperations(userEntities, + userCredentials, PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(), + this.allowedOrigins)); } } From e61544c3976b92b0c7ba132120da291e8e4f8f42 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 18 Apr 2025 17:07:17 +0800 Subject: [PATCH 169/504] Improve OAuth2ResourceServerConfigurer to eliminate deprecated operations Signed-off-by: Yanming Zhou --- .../resource/OAuth2ResourceServerConfigurer.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index e9a425d46d..f5ed36f790 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -138,6 +138,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy; * @author Josh Cummings * @author Evgeniy Cheban * @author Jerome Wacongne <ch4mp@c4-soft.com> + * @author Yanming Zhou * @since 5.1 * @see BearerTokenAuthenticationFilter * @see JwtAuthenticationProvider @@ -490,8 +491,10 @@ public final class OAuth2ResourceServerConfigurer new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId, - this.clientSecret); + this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri) + .clientId(this.clientId) + .clientSecret(this.clientSecret) + .build(); return this; } @@ -500,8 +503,10 @@ public final class OAuth2ResourceServerConfigurer new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId, - this.clientSecret); + this.introspector = () -> SpringOpaqueTokenIntrospector.withIntrospectionUri(this.introspectionUri) + .clientId(this.clientId) + .clientSecret(this.clientSecret) + .build(); return this; } From 45b453f59b21816f9576d608c0ec8be956ae6175 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:38:19 -0600 Subject: [PATCH 170/504] Add ACL Migration Steps --- docs/modules/ROOT/pages/migration-7/acl.adoc | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/modules/ROOT/pages/migration-7/acl.adoc diff --git a/docs/modules/ROOT/pages/migration-7/acl.adoc b/docs/modules/ROOT/pages/migration-7/acl.adoc new file mode 100644 index 0000000000..97c79e768f --- /dev/null +++ b/docs/modules/ROOT/pages/migration-7/acl.adoc @@ -0,0 +1,7 @@ += ACL + +== Favor `AclPermissionEvaluator` + +`AclEntryVoter`, `AclEntryAfterInvocationProvider`, and `AclPermissionEvaluator` provide the same service, plugged into different Spring Security APIs. Now that `AccessDecisionVoter` and `AfterInvocationProvider` are both deprecated, the corresponding ACL plugins are obsolete. + +As such, begin using `AclPermissionEvaluator` before updating to Spring Security 7. From c6bba384580303700bf641dbd64aafa8412a5ce2 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:38:32 -0600 Subject: [PATCH 171/504] Update SAML 2.0 Migration Steps --- .../modules/ROOT/pages/migration-7/saml2.adoc | 239 ++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/docs/modules/ROOT/pages/migration-7/saml2.adoc b/docs/modules/ROOT/pages/migration-7/saml2.adoc index eed236a64b..43da1be2b0 100644 --- a/docs/modules/ROOT/pages/migration-7/saml2.adoc +++ b/docs/modules/ROOT/pages/migration-7/saml2.adoc @@ -1,5 +1,17 @@ = Saml 2.0 Migrations +== Use OpenSAML 5 By Default + +OpenSAML 4.x is no longer supported by the OpenSAML team. +As such, Spring Security will default to using its `OpenSaml5` components in all cases. + +If you want to see how well your application will respond to this, do the following: + +1. Update your OpenSAML dependencies to 5.x +2. If you are constructing an `OpenSaml4XXX` Spring Security component, change it to `OpenSaml5`. + +If you cannot opt-in, then add the `opensaml-saml-api` and `opensaml-saml-impl` 4.x dependencies and exclude the 5.x dependencies from `spring-security-saml2-service-provider`. + == 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. @@ -163,3 +175,230 @@ val responseValidator = ResponseValidator.withDefaults { responseToken: Response provider.setResponseValidator(responseValidator) ---- ====== + +== `RelyingPartyRegistration` Improvements + +`RelyingPartyRegistration` links metadata from a relying party to metadata from an asserting party. + +To prepare for some improvements to the API, please take the following steps: + +1. If you are mutating a registration by using `RelyingPartyRegistration#withRelyingPartyRegistration`, instead call `RelyingPartyRegistration#mutate` +2. If you are providing or retrieving `AssertingPartyDetails`, use `getAssertingPartyMetadata` or `withAssertingPartyMetadata` instead. + +== `OpenSaml5AuthenticationProvider` Improvements + +Spring Security 7 will remove a handful of static factories from `OpenSaml5AuthenticationProvider` in favor of inner classes. +These inner classes simplify customization of the response validator, the assertion validator, and the response authentication converter. + +=== Response Validation + +Instead of doing: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +OpenSaml5AuthenticationProvider saml2AuthenticationProvider() { + OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider(); + saml2.setResponseValidator((responseToken) -> OpenSamlAuthenticationProvider.createDefaultResponseValidator() + .andThen((result) -> result + .concat(myCustomValidator.convert(responseToken)) + )); + return saml2; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider { + val saml2 = OpenSaml5AuthenticationProvider() + saml2.setResponseValidator { responseToken -> OpenSamlAuthenticationProvider.createDefaultResponseValidator() + .andThen { result -> result + .concat(myCustomValidator.convert(responseToken)) + } + } + return saml2 +} +---- +====== + +use `OpenSaml5AuthenticationProvider.ResponseValidator`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +OpenSaml5AuthenticationProvider saml2AuthenticationProvider() { + OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider(); + saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator)); + return saml2; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider { + val saml2 = OpenSaml5AuthenticationProvider() + saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator)) + return saml2 +} +---- +====== + +=== Assertion Validation + +Instead of doing: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +OpenSaml5AuthenticationProvider saml2AuthenticationProvider() { + OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider(); + authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider + .createDefaultAssertionValidatorWithParameters(assertionToken -> { + Map params = new HashMap<>(); + params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis()); + // ... other validation parameters + return new ValidationContext(params); + }) + ); + return saml2; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider { + val saml2 = OpenSaml5AuthenticationProvider() + authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider + .createDefaultAssertionValidatorWithParameters { -> + val params = HashMap() + params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis()) + // ... other validation parameters + return ValidationContext(params) + } + ) + return saml2 +} +---- +====== + +use `OpenSaml5AuthenticationProvider.AssertionValidator`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +OpenSaml5AuthenticationProvider saml2AuthenticationProvider() { + OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider(); + Duration tenMinutes = Duration.ofMinutes(10); + authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build()); + return saml2; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider { + val saml2 = OpenSaml5AuthenticationProvider() + val tenMinutes = Duration.ofMinutes(10) + authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build()) + return saml2 +} +---- +====== + +== Response Authentication Converter + +Instead of doing: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +Converter authenticationConverter() { + return (responseToken) -> { + Saml2Authentication authentication = OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter() + .convert(responseToken); + // ... work with OpenSAML's Assertion object to extract the principal + return new Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities()); + }; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationConverter(): Converter { + return { responseToken -> + val authentication = + OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken) + // ... work with OpenSAML's Assertion object to extract the principal + return Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities()) + } +} +---- +====== + +use `OpenSaml5AuthenticationProvider.ResponseAuthenticationConverter`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +ResponseAuthenticationConverter authenticationConverter() { + ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter(); + authenticationConverter.setPrincipalNameConverter((assertion) -> { + // ... work with OpenSAML's Assertion object to extract the principal + }); + return authenticationConverter; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationConverter(): ResponseAuthenticationConverter { + val authenticationConverter = ResponseAuthenticationConverter() + authenticationConverter.setPrincipalNameConverter { assertion -> + // ... work with OpenSAML's Assertion object to extract the principal + } + return authenticationConverter +} +---- +====== From 084990736e55f5dea2e9edc825bfba72329a4342 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:39:16 -0600 Subject: [PATCH 172/504] Move Opaque Token Migration Steps --- .../pages/migration-7/authentication.adoc | 66 ------------------ .../ROOT/pages/migration-7/oauth2.adoc | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/docs/modules/ROOT/pages/migration-7/authentication.adoc b/docs/modules/ROOT/pages/migration-7/authentication.adoc index 9c5407ae00..7034702b5a 100644 --- a/docs/modules/ROOT/pages/migration-7/authentication.adoc +++ b/docs/modules/ROOT/pages/migration-7/authentication.adoc @@ -1,68 +1,2 @@ = 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/oauth2.adoc b/docs/modules/ROOT/pages/migration-7/oauth2.adoc index 1c3b9b43e2..95cdc1bf71 100644 --- a/docs/modules/ROOT/pages/migration-7/oauth2.adoc +++ b/docs/modules/ROOT/pages/migration-7/oauth2.adoc @@ -170,3 +170,70 @@ fun jwtDecoder(): JwtDecoder { <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. + +== 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) +} +---- +====== From 74a25c3fc18901853f5c59f173a935d861aff681 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:40:10 -0600 Subject: [PATCH 173/504] Add shouldFilterAllDispatcherTypes Migration Steps --- .../ROOT/pages/migration-7/configuration.adoc | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/docs/modules/ROOT/pages/migration-7/configuration.adoc b/docs/modules/ROOT/pages/migration-7/configuration.adoc index 0a06694f95..8d84e04ab4 100644 --- a/docs/modules/ROOT/pages/migration-7/configuration.adoc +++ b/docs/modules/ROOT/pages/migration-7/configuration.adoc @@ -123,3 +123,60 @@ In versions prior to 6.2, if you had a xref:servlet/configuration/java.adoc#jc-c 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]. + +== Use `dispatcherTypeMatchers` instead of `shouldFilterAllDispatcherTypes` + +If you are permitting the ERROR dispatch, you may be using `shouldFilterAllDispatcherTypes(false)` in the `auhorizeHttpRequests` DSL: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +http + .authorizeHttpRequests((authorize) -> authorize + .shouldFilterAllDispatcherTypes(false) + // ... + ) +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +http { + authorizeHttpRequests { + shouldFilterAllDispatcherTypes = false + // ... + } +} +---- +====== + +In preparation for 7, change this to use `dispatcherTypeMatchers`: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +http + .authorizHttpRequests((authorize) -> authorize + .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() + // ... + ) +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +http { + authorizeHttpRequests { + authorize(new DispatcherTypeRequestMatcher(DispatcherType.ERROR), permitAll()) + } +} +---- +====== From 84db5bb312d6afb2db38ab89278c350f48a0017d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:43:04 -0600 Subject: [PATCH 174/504] Add Cookie Customizer Migration Steps --- docs/modules/ROOT/pages/migration-7/web.adoc | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/modules/ROOT/pages/migration-7/web.adoc b/docs/modules/ROOT/pages/migration-7/web.adoc index 467f2663e8..248b719c0e 100644 --- a/docs/modules/ROOT/pages/migration-7/web.adoc +++ b/docs/modules/ROOT/pages/migration-7/web.adoc @@ -521,3 +521,49 @@ Xml:: ===== If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance. ===== + +== Use `setCookieCustomizer` instead of individual setters + +In favor of a simpler API, `CookieCsrfTokenRepository#setCookieCustomizer` allows you to change any aspect of the cookie, replacing `setCookieHttpOnly`, `setCookieMaxAge`, `setSecure`, and `setCookieDomain`. + +Change this: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse(); +csrf.setCookieMaxAge(86400) +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse() +csrf.setCookieMaxAge(86400) +---- +====== + +to this: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse(); +csrf.setCookieCustomizer((c) -> c.maxAge(86400)); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse() +csrf.setCookieCustomizer { -> it.maxAge(86400) } +---- +====== From 211b1b7285f2994fc1dd24a442d15bde20e4b1ab Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:44:20 -0600 Subject: [PATCH 175/504] Update Method Security Migration Steps --- .../ROOT/pages/migration-7/authorization.adoc | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/modules/ROOT/pages/migration-7/authorization.adoc b/docs/modules/ROOT/pages/migration-7/authorization.adoc index 031c8a8bfb..0c0801285c 100644 --- a/docs/modules/ROOT/pages/migration-7/authorization.adoc +++ b/docs/modules/ROOT/pages/migration-7/authorization.adoc @@ -22,3 +22,82 @@ 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]. + +=== Favor `AnnotationTemplateExpressionDefaults` over `PrePostTemplateDefaults` + +In Spring Security 7, `AnnotationTemplateExpressionDefaults` will be included by default. + +If you are customizing `PrePostTemplateDefaults` or simply want to see how your application responds to `AnnotationTemplateExpressionDefaults`, you can publish an `AnnotationTemplateExpressionDefaults` bean instead of a `PrePostTemplateDefaults` method: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +static AnnotationTemplateExpressionDefaults templateExpressionDefaults() { + return new AnnotationTemplateExpressionDefaults(); +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +companion object { + @Bean + fun templateExpressionDefaults() = AnnotationTemplateExpressionDefaults() +} +---- + +Xml:: ++ +[source,xml,role="secondary"] +---- + +---- +====== + +==== I Am Publishing an AuthorizationAdvisor Bean + +If you are publishing an `AuthorizationAdvisor` bean, like `AuthorizationManagerBeforeMethodInterceptor`, `AuthorizationManagerAfterMethodInterceptor`, `PreFilterAuthorizationMethodInterceptor`, or `PostFilterAuthorizationMethodInterceptor`, you can do the same by calling `setTemplateDefaults` with an `AnnotationTemplateExpressionDefaults` instance instead: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +@Role(BeanDescription.ROLE_INFRASTRUCTURE) +static Advisor preFilter() { + PreFilterAuthorizationMethodInterceptor interceptor = new PreFilterAuthorizationMethodInterceptor(); + interceptor.setTemplateDefaults(new AnnotationTemplateExpressionDefaults()); + return interceptor; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +companion object { + @Bean + @Role(BeanDescription.ROLE_INFRASTRUCTURE) + fun preFilter(): Advisor { + val interceptor = PreFilterAuthorizationMethodInterceptor() + interceptor.setTemplateDefaults(AnnotationTemplateExpressionDefaults) + return interceptor + } +} +---- +====== + +=== Publish `AuthorizationAdvisor` instances instead of adding them in a `Customizer` + +While the ability to customize the `AuthorizationAdvisorProxyFactory` instance will remain in Spring Security 7, the ability to add advisors will be removed in favor of picking up published `AuthorizationAdvisor` beans. + +If you are not calling `AuthorizationAdvisorProxyFactory#setAdvisors` or `AuthorizationAdvisorProxyFactory#addAdvisor`, you need do nothing. + +If you are, publish the `AuthorizationAdvisor` bean instead and Spring Security will pick it up and apply it automatically. From 1ec084886a6585dc159c609aeff7e7917a7ed330 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 6 May 2025 16:55:22 -0600 Subject: [PATCH 176/504] Revert "Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.19.0" This reverts commit 226e81d7f55d38603f3f179d3e32caf3e7ed6a20. Given that we are in the RC phase, we do not want to do minor version upgrades --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 56d8410fd6..1a547b7152 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "6.2.6" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.3" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 8fcf181ff01d3875a315c4a90591f1a5a55e4366 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 03:30:49 +0000 Subject: [PATCH 177/504] Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.18.4 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.3 to 2.18.4. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.3...jackson-bom-2.18.4) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.18.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 480783386d..9246c0a9d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "6.2.6" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.3" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From de622d108254d79708c725102aec607896c60283 Mon Sep 17 00:00:00 2001 From: Shenker93 Date: Sat, 24 Feb 2024 09:30:28 +0200 Subject: [PATCH 178/504] Improve JdbcUserDetailsManager.userExists method --- .../provisioning/JdbcUserDetailsManager.java | 13 +++++++------ .../provisioning/JdbcUserDetailsManagerTests.java | 5 +++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index 59c0147da5..5856580cce 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -77,7 +77,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa public static final String DEF_DELETE_USER_AUTHORITIES_SQL = "delete from authorities where username = ?"; - public static final String DEF_USER_EXISTS_SQL = "select username from users where username = ?"; + public static final String DEF_USER_EXISTS_SQL = "select count(*) from users where username = ?"; public static final String DEF_CHANGE_PASSWORD_SQL = "update users set password = ? where username = ?"; @@ -337,12 +337,13 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa @Override public boolean userExists(String username) { - List users = requireJdbcTemplate().queryForList(this.userExistsSql, String.class, username); - if (users.size() > 1) { - throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", - 1); + @SuppressWarnings("ConstantConditions") + int usersCount = getJdbcTemplate().queryForObject(this.userExistsSql, Integer.class, username); + if (usersCount > 1) { + throw new IncorrectResultSizeDataAccessException( + "[" + usersCount + "] users found with name '" + username + "', expected 1", 1); } - return users.size() == 1; + return usersCount == 1; } @Override diff --git a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java index fb89d191f1..5c8ed72b18 100644 --- a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java @@ -189,6 +189,11 @@ public class JdbcUserDetailsManagerTests { assertThat(this.manager.userExists("joe")).isFalse(); } + @Test + public void userExistsReturnsFalseForNullUsername() { + assertThat(this.manager.userExists(null)).isFalse(); + } + @Test public void userExistsReturnsTrueForExistingUsername() { insertJoe(); From 7fda87aecd01d9628eb89be1e06b0c92ef9bf399 Mon Sep 17 00:00:00 2001 From: milaneuh Date: Tue, 14 Nov 2023 15:36:53 +0100 Subject: [PATCH 179/504] Remove deprecated methods from CookieServerCsrfTokenRepository --- .../web/csrf/CookieCsrfTokenRepository.java | 36 ------------------- .../csrf/CookieCsrfTokenRepositoryTests.java | 14 ++++---- 2 files changed, 7 insertions(+), 43 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java index 546ccd94d0..da7f0f0939 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CookieCsrfTokenRepository.java @@ -169,14 +169,6 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { this.cookieName = cookieName; } - /** - * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead. - */ - @Deprecated(since = "6.1") - public void setCookieHttpOnly(boolean cookieHttpOnly) { - this.cookieHttpOnly = cookieHttpOnly; - } - private String getRequestContext(HttpServletRequest request) { String contextPath = request.getContextPath(); return (contextPath.length() > 0) ? contextPath : "/"; @@ -230,32 +222,4 @@ public final class CookieCsrfTokenRepository implements CsrfTokenRepository { return this.cookiePath; } - /** - * @since 5.2 - * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead. - */ - @Deprecated(since = "6.1") - public void setCookieDomain(String cookieDomain) { - this.cookieDomain = cookieDomain; - } - - /** - * @since 5.4 - * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead. - */ - @Deprecated(since = "6.1") - public void setSecure(Boolean secure) { - this.secure = secure; - } - - /** - * @since 5.5 - * @deprecated Use {@link #setCookieCustomizer(Consumer)} instead. - */ - @Deprecated(since = "6.1") - public void setCookieMaxAge(int cookieMaxAge) { - Assert.isTrue(cookieMaxAge != 0, "cookieMaxAge cannot be zero"); - this.cookieMaxAge = cookieMaxAge; - } - } diff --git a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java index bc2088e53c..1f88a2042a 100644 --- a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java @@ -112,7 +112,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenSecureFlagTrue() { this.request.setSecure(false); - this.repository.setSecure(Boolean.TRUE); + this.repository.setCookieCustomizer((cookie)-> cookie.secure(Boolean.TRUE)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -132,7 +132,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenSecureFlagFalse() { this.request.setSecure(true); - this.repository.setSecure(Boolean.FALSE); + this.repository.setCookieCustomizer((cookie)-> cookie.secure(Boolean.FALSE)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -163,7 +163,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenHttpOnlyTrue() { - this.repository.setCookieHttpOnly(true); + this.repository.setCookieCustomizer((cookie) -> cookie.httpOnly(true)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -181,7 +181,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenHttpOnlyFalse() { - this.repository.setCookieHttpOnly(false); + this.repository.setCookieCustomizer((cookie) -> cookie.httpOnly(false)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -239,7 +239,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenWithCookieDomain() { String domainName = "example.com"; - this.repository.setCookieDomain(domainName); + this.repository.setCookieCustomizer((cookie) -> cookie.domain(domainName)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -259,7 +259,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenWithCookieMaxAge() { int maxAge = 1200; - this.repository.setCookieMaxAge(maxAge); + this.repository.setCookieCustomizer((cookie) -> cookie.maxAge(maxAge)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -506,7 +506,7 @@ class CookieCsrfTokenRepositoryTests { @Test void setCookieMaxAgeZeroIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieMaxAge(0)); + assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieCustomizer((cookie) -> cookie.maxAge(0))); } } From 5f833fa2364fa3d874286b7a8d3a435762ca26a9 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 7 May 2025 10:19:05 -0500 Subject: [PATCH 180/504] Fix Checkstyle Errors --- .../web/csrf/CookieCsrfTokenRepositoryTests.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java index 1f88a2042a..2c870332f1 100644 --- a/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/csrf/CookieCsrfTokenRepositoryTests.java @@ -112,7 +112,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenSecureFlagTrue() { this.request.setSecure(false); - this.repository.setCookieCustomizer((cookie)-> cookie.secure(Boolean.TRUE)); + this.repository.setCookieCustomizer((cookie) -> cookie.secure(Boolean.TRUE)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -132,7 +132,7 @@ class CookieCsrfTokenRepositoryTests { @Test void saveTokenSecureFlagFalse() { this.request.setSecure(true); - this.repository.setCookieCustomizer((cookie)-> cookie.secure(Boolean.FALSE)); + this.repository.setCookieCustomizer((cookie) -> cookie.secure(Boolean.FALSE)); CsrfToken token = this.repository.generateToken(this.request); this.repository.saveToken(token, this.request, this.response); Cookie tokenCookie = this.response.getCookie(CookieCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME); @@ -504,9 +504,4 @@ class CookieCsrfTokenRepositoryTests { assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setHeaderName(null)); } - @Test - void setCookieMaxAgeZeroIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.repository.setCookieCustomizer((cookie) -> cookie.maxAge(0))); - } - } From 2b22cf287788e9a0b48c241d7c31770d2dbe1474 Mon Sep 17 00:00:00 2001 From: Ferdinand Jacobs Date: Mon, 25 Nov 2024 18:49:52 +0100 Subject: [PATCH 181/504] Replace BouncyCastle's deprecated AESFastEngine with the default AESEngine - Update AESEngine to use the default AES engine, following BouncyCastle's recommendations (see release-1-56 of changelog: https://www.bouncycastle.org/download/bouncy-castle-java/?filter=java%3Drelease-1-56). - Migrate to the latest API 'newInstance()' method to allow removal of @SuppressWarnings("deprecation") - Remove @SuppressWarnings("deprecation") --- .../crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java | 7 +++---- .../crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java index 3aa6e6eab3..3fde93d5ea 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java @@ -18,6 +18,7 @@ package org.springframework.security.crypto.encrypt; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PKCS7Padding; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; @@ -45,23 +46,21 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp } @Override - @SuppressWarnings("deprecation") public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( - new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding()); + CBCBlockCipher.newInstance(AESEngine.newInstance()), new PKCS7Padding()); blockCipher.init(true, new ParametersWithIV(this.secretKey, iv)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; } @Override - @SuppressWarnings("deprecation") public byte[] decrypt(byte[] encryptedBytes) { byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( - new CBCBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()), new PKCS7Padding()); + CBCBlockCipher.newInstance(AESEngine.newInstance()), new PKCS7Padding()); blockCipher.init(false, new ParametersWithIV(this.secretKey, iv)); return process(blockCipher, encryptedBytes); } diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java index cce6dd6d99..20ccf9265e 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java @@ -17,6 +17,7 @@ package org.springframework.security.crypto.encrypt; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; @@ -44,21 +45,19 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp } @Override - @SuppressWarnings("deprecation") public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); - GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()); + GCMBlockCipher blockCipher = (GCMBlockCipher) GCMBlockCipher.newInstance(AESEngine.newInstance()); blockCipher.init(true, new AEADParameters(this.secretKey, 128, iv, null)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; } @Override - @SuppressWarnings("deprecation") public byte[] decrypt(byte[] encryptedBytes) { byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); - GCMBlockCipher blockCipher = new GCMBlockCipher(new org.bouncycastle.crypto.engines.AESFastEngine()); + GCMBlockCipher blockCipher = (GCMBlockCipher) GCMBlockCipher.newInstance(AESEngine.newInstance()); blockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null)); return process(blockCipher, encryptedBytes); } From 5eb232cd3d0d09a7eac83e24a265079380f25647 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:33:00 -0600 Subject: [PATCH 182/504] Polish gh-16164 --- .../BouncyCastleAesCbcBytesEncryptor.java | 29 +++++-- .../BouncyCastleAesGcmBytesEncryptor.java | 25 +++++- ...stleAesBytesEncryptorEquivalencyTests.java | 85 ++++++++++++++++++- 3 files changed, 129 insertions(+), 10 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java index 3fde93d5ea..362f28c255 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2016 the original author or authors. + * Copyright 2011-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,14 @@ package org.springframework.security.crypto.encrypt; +import java.util.function.Supplier; + import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.modes.CBCModeCipher; import org.bouncycastle.crypto.paddings.PKCS7Padding; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -37,6 +41,8 @@ import org.springframework.security.crypto.util.EncodingUtils; */ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryptor { + private Supplier cipherFactory = () -> CBCBlockCipher.newInstance(AESEngine.newInstance()); + public BouncyCastleAesCbcBytesEncryptor(String password, CharSequence salt) { super(password, salt); } @@ -48,8 +54,8 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp @Override public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); - PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( - CBCBlockCipher.newInstance(AESEngine.newInstance()), new PKCS7Padding()); + PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(this.cipherFactory.get(), + new PKCS7Padding()); blockCipher.init(true, new ParametersWithIV(this.secretKey, iv)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; @@ -59,8 +65,8 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp public byte[] decrypt(byte[] encryptedBytes) { byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); - PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher( - CBCBlockCipher.newInstance(AESEngine.newInstance()), new PKCS7Padding()); + PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(this.cipherFactory.get(), + new PKCS7Padding()); blockCipher.init(false, new ParametersWithIV(this.secretKey, iv)); return process(blockCipher, encryptedBytes); } @@ -82,4 +88,17 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp return out; } + /** + * Used to test compatibility with deprecated {@link AESFastEngine}. + */ + @SuppressWarnings("deprecation") + static BouncyCastleAesCbcBytesEncryptor withAESFastEngine(String password, CharSequence salt, + BytesKeyGenerator ivGenerator) { + BouncyCastleAesCbcBytesEncryptor bytesEncryptor = new BouncyCastleAesCbcBytesEncryptor(password, salt, + ivGenerator); + bytesEncryptor.cipherFactory = () -> new CBCBlockCipher(new AESFastEngine()); + + return bytesEncryptor; + } + } diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java index 20ccf9265e..52d6e6cc48 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2016 the original author or authors. + * Copyright 2011-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,11 @@ package org.springframework.security.crypto.encrypt; +import java.util.function.Supplier; + import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; @@ -36,6 +39,9 @@ import org.springframework.security.crypto.util.EncodingUtils; */ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryptor { + private Supplier cipherFactory = () -> (GCMBlockCipher) GCMBlockCipher + .newInstance(AESEngine.newInstance()); + public BouncyCastleAesGcmBytesEncryptor(String password, CharSequence salt) { super(password, salt); } @@ -47,7 +53,7 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp @Override public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); - GCMBlockCipher blockCipher = (GCMBlockCipher) GCMBlockCipher.newInstance(AESEngine.newInstance()); + AEADBlockCipher blockCipher = this.cipherFactory.get(); blockCipher.init(true, new AEADParameters(this.secretKey, 128, iv, null)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; @@ -57,7 +63,7 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp public byte[] decrypt(byte[] encryptedBytes) { byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); - GCMBlockCipher blockCipher = (GCMBlockCipher) GCMBlockCipher.newInstance(AESEngine.newInstance()); + AEADBlockCipher blockCipher = this.cipherFactory.get(); blockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null)); return process(blockCipher, encryptedBytes); } @@ -79,4 +85,17 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp return out; } + /** + * Used to test compatibility with deprecated {@link AESFastEngine}. + */ + @SuppressWarnings("deprecation") + static BouncyCastleAesGcmBytesEncryptor withAESFastEngine(String password, CharSequence salt, + BytesKeyGenerator ivGenerator) { + BouncyCastleAesGcmBytesEncryptor bytesEncryptor = new BouncyCastleAesGcmBytesEncryptor(password, salt, + ivGenerator); + bytesEncryptor.cipherFactory = () -> new GCMBlockCipher(new AESFastEngine()); + + return bytesEncryptor; + } + } diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java index a37c83092c..0dda6ebfc5 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2021 the original author or authors. + * Copyright 2011-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,14 @@ package org.springframework.security.crypto.encrypt; import java.security.SecureRandom; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Random; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.springframework.security.crypto.codec.Hex; @@ -89,6 +93,64 @@ public class BouncyCastleAesBytesEncryptorEquivalencyTests { testCompatibility(bcEncryptor, jceEncryptor); } + @Test + public void bouncyCastleAesGcmWithAESFastEngineCompatible() throws Exception { + CryptoAssumptions.assumeGCMJCE(); + BytesEncryptor fastEngineEncryptor = BouncyCastleAesGcmBytesEncryptor.withAESFastEngine(this.password, + this.salt, KeyGenerators.secureRandom(16)); + BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesGcmBytesEncryptor(this.password, this.salt, + KeyGenerators.secureRandom(16)); + testCompatibility(fastEngineEncryptor, defaultEngineEncryptor); + } + + @Test + public void bouncyCastleAesCbcWithAESFastEngineCompatible() throws Exception { + CryptoAssumptions.assumeCBCJCE(); + BytesEncryptor fastEngineEncryptor = BouncyCastleAesCbcBytesEncryptor.withAESFastEngine(this.password, + this.salt, KeyGenerators.secureRandom(16)); + BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesCbcBytesEncryptor(this.password, this.salt, + KeyGenerators.secureRandom(16)); + testCompatibility(fastEngineEncryptor, defaultEngineEncryptor); + } + + /** + * Comment out @Disabled below to compare relative speed of deprecated AESFastEngine + * with the default AESEngine. + */ + @Disabled + @RepeatedTest(100) + public void bouncyCastleAesGcmWithAESFastEngineSpeedTest() throws Exception { + CryptoAssumptions.assumeGCMJCE(); + BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesGcmBytesEncryptor(this.password, this.salt, + KeyGenerators.secureRandom(16)); + BytesEncryptor fastEngineEncryptor = BouncyCastleAesGcmBytesEncryptor.withAESFastEngine(this.password, + this.salt, KeyGenerators.secureRandom(16)); + long defaultNanos = testSpeed(defaultEngineEncryptor); + long fastNanos = testSpeed(fastEngineEncryptor); + System.out.println(nanosToReadableString("AES GCM w/Default Engine", defaultNanos)); + System.out.println(nanosToReadableString("AES GCM w/ Fast Engine", fastNanos)); + assertThat(fastNanos).isLessThan(defaultNanos); + } + + /** + * Comment out @Disabled below to compare relative speed of deprecated AESFastEngine + * with the default AESEngine. + */ + @Disabled + @RepeatedTest(100) + public void bouncyCastleAesCbcWithAESFastEngineSpeedTest() throws Exception { + CryptoAssumptions.assumeCBCJCE(); + BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesCbcBytesEncryptor(this.password, this.salt, + KeyGenerators.secureRandom(16)); + BytesEncryptor fastEngineEncryptor = BouncyCastleAesCbcBytesEncryptor.withAESFastEngine(this.password, + this.salt, KeyGenerators.secureRandom(16)); + long defaultNanos = testSpeed(defaultEngineEncryptor); + long fastNanos = testSpeed(fastEngineEncryptor); + System.out.println(nanosToReadableString("AES CBC w/Default Engine", defaultNanos)); + System.out.println(nanosToReadableString("AES CBC w/ Fast Engine", fastNanos)); + assertThat(fastNanos).isLessThan(defaultNanos); + } + private void testEquivalence(BytesEncryptor left, BytesEncryptor right) { for (int size = 1; size < 2048; size++) { this.testData = new byte[size]; @@ -107,7 +169,7 @@ public class BouncyCastleAesBytesEncryptorEquivalencyTests { private void testCompatibility(BytesEncryptor left, BytesEncryptor right) { // tests that right can decrypt what left encrypted and vice versa - // and that the decypted data is the same as the original + // and that the decrypted data is the same as the original for (int size = 1; size < 2048; size++) { this.testData = new byte[size]; this.secureRandom.nextBytes(this.testData); @@ -120,6 +182,25 @@ public class BouncyCastleAesBytesEncryptorEquivalencyTests { } } + private long testSpeed(BytesEncryptor bytesEncryptor) { + long start = System.nanoTime(); + for (int size = 0; size < 2048; size++) { + this.testData = new byte[size]; + this.secureRandom.nextBytes(this.testData); + byte[] encrypted = bytesEncryptor.encrypt(this.testData); + byte[] decrypted = bytesEncryptor.decrypt(encrypted); + assertThat(decrypted).containsExactly(this.testData); + } + return System.nanoTime() - start; + } + + private String nanosToReadableString(String label, long nanos) { + Duration duration = Duration.ofNanos(nanos); + Duration millis = duration.truncatedTo(ChronoUnit.MILLIS); + Duration micros = duration.minus(millis).dividedBy(1000); + return "%s: %dms %dμs".formatted(label, duration.toMillis(), micros.toNanos()); + } + /** * A BytesKeyGenerator that always generates the same sequence of values */ From d52289bd7a27acae736a44737ff636ab21a2d2ca Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 7 May 2025 10:54:55 -0500 Subject: [PATCH 183/504] Remove Unnecessary Backwards Compatability Since this is going to be merged into Spring Security 7 (a major release) and AESFastEngine is deprecated, we should no longer support it (as it will likely be removed from Bouncy Castle) --- .../BouncyCastleAesCbcBytesEncryptor.java | 26 ++------ .../BouncyCastleAesGcmBytesEncryptor.java | 23 +------ ...stleAesBytesEncryptorEquivalencyTests.java | 60 ------------------- 3 files changed, 6 insertions(+), 103 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java index 362f28c255..565ec4d3c1 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesCbcBytesEncryptor.java @@ -16,12 +16,9 @@ package org.springframework.security.crypto.encrypt; -import java.util.function.Supplier; - import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.CBCModeCipher; import org.bouncycastle.crypto.paddings.PKCS7Padding; @@ -41,8 +38,6 @@ import org.springframework.security.crypto.util.EncodingUtils; */ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryptor { - private Supplier cipherFactory = () -> CBCBlockCipher.newInstance(AESEngine.newInstance()); - public BouncyCastleAesCbcBytesEncryptor(String password, CharSequence salt) { super(password, salt); } @@ -54,8 +49,8 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp @Override public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); - PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(this.cipherFactory.get(), - new PKCS7Padding()); + CBCModeCipher cbcModeCipher = CBCBlockCipher.newInstance(AESEngine.newInstance()); + PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(cbcModeCipher, new PKCS7Padding()); blockCipher.init(true, new ParametersWithIV(this.secretKey, iv)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; @@ -63,10 +58,10 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp @Override public byte[] decrypt(byte[] encryptedBytes) { + CBCModeCipher cbcModeCipher = CBCBlockCipher.newInstance(AESEngine.newInstance()); byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); - PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(this.cipherFactory.get(), - new PKCS7Padding()); + PaddedBufferedBlockCipher blockCipher = new PaddedBufferedBlockCipher(cbcModeCipher, new PKCS7Padding()); blockCipher.init(false, new ParametersWithIV(this.secretKey, iv)); return process(blockCipher, encryptedBytes); } @@ -88,17 +83,4 @@ public class BouncyCastleAesCbcBytesEncryptor extends BouncyCastleAesBytesEncryp return out; } - /** - * Used to test compatibility with deprecated {@link AESFastEngine}. - */ - @SuppressWarnings("deprecation") - static BouncyCastleAesCbcBytesEncryptor withAESFastEngine(String password, CharSequence salt, - BytesKeyGenerator ivGenerator) { - BouncyCastleAesCbcBytesEncryptor bytesEncryptor = new BouncyCastleAesCbcBytesEncryptor(password, salt, - ivGenerator); - bytesEncryptor.cipherFactory = () -> new CBCBlockCipher(new AESFastEngine()); - - return bytesEncryptor; - } - } diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java index 52d6e6cc48..15eb61ad70 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java @@ -16,11 +16,8 @@ package org.springframework.security.crypto.encrypt; -import java.util.function.Supplier; - import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; import org.bouncycastle.crypto.params.AEADParameters; @@ -39,9 +36,6 @@ import org.springframework.security.crypto.util.EncodingUtils; */ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryptor { - private Supplier cipherFactory = () -> (GCMBlockCipher) GCMBlockCipher - .newInstance(AESEngine.newInstance()); - public BouncyCastleAesGcmBytesEncryptor(String password, CharSequence salt) { super(password, salt); } @@ -53,7 +47,7 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp @Override public byte[] encrypt(byte[] bytes) { byte[] iv = this.ivGenerator.generateKey(); - AEADBlockCipher blockCipher = this.cipherFactory.get(); + AEADBlockCipher blockCipher = GCMBlockCipher.newInstance(AESEngine.newInstance()); blockCipher.init(true, new AEADParameters(this.secretKey, 128, iv, null)); byte[] encrypted = process(blockCipher, bytes); return (iv != null) ? EncodingUtils.concatenate(iv, encrypted) : encrypted; @@ -63,7 +57,7 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp public byte[] decrypt(byte[] encryptedBytes) { byte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength()); encryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length); - AEADBlockCipher blockCipher = this.cipherFactory.get(); + AEADBlockCipher blockCipher = GCMBlockCipher.newInstance(AESEngine.newInstance()); blockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null)); return process(blockCipher, encryptedBytes); } @@ -85,17 +79,4 @@ public class BouncyCastleAesGcmBytesEncryptor extends BouncyCastleAesBytesEncryp return out; } - /** - * Used to test compatibility with deprecated {@link AESFastEngine}. - */ - @SuppressWarnings("deprecation") - static BouncyCastleAesGcmBytesEncryptor withAESFastEngine(String password, CharSequence salt, - BytesKeyGenerator ivGenerator) { - BouncyCastleAesGcmBytesEncryptor bytesEncryptor = new BouncyCastleAesGcmBytesEncryptor(password, salt, - ivGenerator); - bytesEncryptor.cipherFactory = () -> new GCMBlockCipher(new AESFastEngine()); - - return bytesEncryptor; - } - } diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java index 0dda6ebfc5..7db08b3378 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java @@ -23,8 +23,6 @@ import java.util.Random; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.springframework.security.crypto.codec.Hex; @@ -93,64 +91,6 @@ public class BouncyCastleAesBytesEncryptorEquivalencyTests { testCompatibility(bcEncryptor, jceEncryptor); } - @Test - public void bouncyCastleAesGcmWithAESFastEngineCompatible() throws Exception { - CryptoAssumptions.assumeGCMJCE(); - BytesEncryptor fastEngineEncryptor = BouncyCastleAesGcmBytesEncryptor.withAESFastEngine(this.password, - this.salt, KeyGenerators.secureRandom(16)); - BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesGcmBytesEncryptor(this.password, this.salt, - KeyGenerators.secureRandom(16)); - testCompatibility(fastEngineEncryptor, defaultEngineEncryptor); - } - - @Test - public void bouncyCastleAesCbcWithAESFastEngineCompatible() throws Exception { - CryptoAssumptions.assumeCBCJCE(); - BytesEncryptor fastEngineEncryptor = BouncyCastleAesCbcBytesEncryptor.withAESFastEngine(this.password, - this.salt, KeyGenerators.secureRandom(16)); - BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesCbcBytesEncryptor(this.password, this.salt, - KeyGenerators.secureRandom(16)); - testCompatibility(fastEngineEncryptor, defaultEngineEncryptor); - } - - /** - * Comment out @Disabled below to compare relative speed of deprecated AESFastEngine - * with the default AESEngine. - */ - @Disabled - @RepeatedTest(100) - public void bouncyCastleAesGcmWithAESFastEngineSpeedTest() throws Exception { - CryptoAssumptions.assumeGCMJCE(); - BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesGcmBytesEncryptor(this.password, this.salt, - KeyGenerators.secureRandom(16)); - BytesEncryptor fastEngineEncryptor = BouncyCastleAesGcmBytesEncryptor.withAESFastEngine(this.password, - this.salt, KeyGenerators.secureRandom(16)); - long defaultNanos = testSpeed(defaultEngineEncryptor); - long fastNanos = testSpeed(fastEngineEncryptor); - System.out.println(nanosToReadableString("AES GCM w/Default Engine", defaultNanos)); - System.out.println(nanosToReadableString("AES GCM w/ Fast Engine", fastNanos)); - assertThat(fastNanos).isLessThan(defaultNanos); - } - - /** - * Comment out @Disabled below to compare relative speed of deprecated AESFastEngine - * with the default AESEngine. - */ - @Disabled - @RepeatedTest(100) - public void bouncyCastleAesCbcWithAESFastEngineSpeedTest() throws Exception { - CryptoAssumptions.assumeCBCJCE(); - BytesEncryptor defaultEngineEncryptor = new BouncyCastleAesCbcBytesEncryptor(this.password, this.salt, - KeyGenerators.secureRandom(16)); - BytesEncryptor fastEngineEncryptor = BouncyCastleAesCbcBytesEncryptor.withAESFastEngine(this.password, - this.salt, KeyGenerators.secureRandom(16)); - long defaultNanos = testSpeed(defaultEngineEncryptor); - long fastNanos = testSpeed(fastEngineEncryptor); - System.out.println(nanosToReadableString("AES CBC w/Default Engine", defaultNanos)); - System.out.println(nanosToReadableString("AES CBC w/ Fast Engine", fastNanos)); - assertThat(fastNanos).isLessThan(defaultNanos); - } - private void testEquivalence(BytesEncryptor left, BytesEncryptor right) { for (int size = 1; size < 2048; size++) { this.testData = new byte[size]; From 23e7c9eeaa9156f488db74d4f1c4f42a5bd1a86c Mon Sep 17 00:00:00 2001 From: kiruthiga1793 Date: Thu, 30 Jan 2025 19:15:43 -0500 Subject: [PATCH 184/504] Add Twitter/X to CommonOAuth2Provider Signed-off-by: kiruthiga1793 --- .../oauth2/client/CommonOAuth2Provider.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java index c51b716e16..7ffffb3a59 100644 --- a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java +++ b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java @@ -87,6 +87,23 @@ public enum CommonOAuth2Provider { }, + X { + + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, + ClientAuthenticationMethod.CLIENT_SECRET_POST, DEFAULT_REDIRECT_URL); + builder.scope("users.read","tweet.read"); + builder.authorizationUri("https://x.com/i/oauth2/authorize"); + builder.tokenUri("https://api.x.com/2/oauth2/token"); + builder.userInfoUri("https://api.x.com/2/users/me"); + builder.userNameAttributeName("username"); + builder.clientName("X"); + return builder; + } + + }, + OKTA { @Override From f13836c9c86d2e4c3bda2f06fe00937a3c8dec0a Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 7 May 2025 11:30:08 -0500 Subject: [PATCH 185/504] Add X to CommonOAuth2Provider Reference Issue gh-16510 Signed-off-by: Rob Winch <362503+rwinch@users.noreply.github.com> --- docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc | 2 +- docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc b/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc index 8ea1642c1b..a98676f846 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc @@ -153,7 +153,7 @@ A `ClientRegistration` can be initially configured using discovery of an OpenID [[webflux-oauth2-login-common-oauth2-provider]] == CommonOAuth2Provider -`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta. +`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, X, and Okta. For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider. Therefore, it makes sense to provide default values in order to reduce the required configuration. diff --git a/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc b/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc index ffcecee7c9..4c179cc62a 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc @@ -153,7 +153,7 @@ You can initially configure a `ClientRegistration` by using discovery of an Open [[oauth2login-common-oauth2-provider]] == CommonOAuth2Provider -`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta. +`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, X, and Okta. For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a provider. Therefore, it makes sense to provide default values, to reduce the required configuration. From 693a5beb2407bc9992acb60a7506271ebd94d422 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 7 May 2025 14:55:04 -0500 Subject: [PATCH 186/504] Format CommonOAuth2Provider --- .../security/config/oauth2/client/CommonOAuth2Provider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java index 7ffffb3a59..96d0e51eac 100644 --- a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java +++ b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java @@ -93,7 +93,7 @@ public enum CommonOAuth2Provider { public Builder getBuilder(String registrationId) { ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_POST, DEFAULT_REDIRECT_URL); - builder.scope("users.read","tweet.read"); + builder.scope("users.read", "tweet.read"); builder.authorizationUri("https://x.com/i/oauth2/authorize"); builder.tokenUri("https://api.x.com/2/oauth2/token"); builder.userInfoUri("https://api.x.com/2/users/me"); From 241c3cd35a286b6127d73ce762db57bced057015 Mon Sep 17 00:00:00 2001 From: M-Faheem-Khan Date: Sun, 27 Apr 2025 23:53:19 -0400 Subject: [PATCH 187/504] Remove deprecated Cookie usage Remove usage of comment and verison usage Signed-off-by: M-Faheem-Khan --- .../AbstractRememberMeServices.java | 3 -- .../web/firewall/FirewalledResponse.java | 1 - .../web/jackson2/CookieDeserializer.java | 2 -- .../web/jackson2/SavedCookieMixin.java | 6 ++-- .../web/savedrequest/SavedCookie.java | 33 +------------------ .../AbstractRememberMeServicesTests.java | 11 ------- .../web/firewall/FirewalledResponseTests.java | 1 - .../DefaultSavedRequestMixinTests.java | 2 -- .../web/jackson2/SavedCookieMixinTests.java | 6 +--- .../web/savedrequest/SavedCookieTests.java | 14 -------- 10 files changed, 4 insertions(+), 75 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java index 30b9e261d0..fd1c38b18a 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java @@ -372,9 +372,6 @@ public abstract class AbstractRememberMeServices if (this.cookieDomain != null) { cookie.setDomain(this.cookieDomain); } - if (maxAge < 1) { - cookie.setVersion(1); - } cookie.setSecure((this.useSecureCookie != null) ? this.useSecureCookie : request.isSecure()); cookie.setHttpOnly(true); diff --git a/web/src/main/java/org/springframework/security/web/firewall/FirewalledResponse.java b/web/src/main/java/org/springframework/security/web/firewall/FirewalledResponse.java index e5d34ff197..12bfacedd3 100644 --- a/web/src/main/java/org/springframework/security/web/firewall/FirewalledResponse.java +++ b/web/src/main/java/org/springframework/security/web/firewall/FirewalledResponse.java @@ -67,7 +67,6 @@ class FirewalledResponse extends HttpServletResponseWrapper { validateCrlf(SET_COOKIE_HEADER, cookie.getValue()); validateCrlf(SET_COOKIE_HEADER, cookie.getPath()); validateCrlf(SET_COOKIE_HEADER, cookie.getDomain()); - validateCrlf(SET_COOKIE_HEADER, cookie.getComment()); } super.addCookie(cookie); } diff --git a/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java b/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java index d4123a8188..99b3bc9d1a 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/CookieDeserializer.java @@ -45,11 +45,9 @@ class CookieDeserializer extends JsonDeserializer { ObjectMapper mapper = (ObjectMapper) jp.getCodec(); JsonNode jsonNode = mapper.readTree(jp); Cookie cookie = new Cookie(readJsonNode(jsonNode, "name").asText(), readJsonNode(jsonNode, "value").asText()); - cookie.setComment(readJsonNode(jsonNode, "comment").asText()); cookie.setDomain(readJsonNode(jsonNode, "domain").asText()); cookie.setMaxAge(readJsonNode(jsonNode, "maxAge").asInt(-1)); cookie.setSecure(readJsonNode(jsonNode, "secure").asBoolean()); - cookie.setVersion(readJsonNode(jsonNode, "version").asInt()); cookie.setPath(readJsonNode(jsonNode, "path").asText()); JsonNode attributes = readJsonNode(jsonNode, "attributes"); cookie.setHttpOnly(readJsonNode(attributes, "HttpOnly") != null); diff --git a/web/src/main/java/org/springframework/security/web/jackson2/SavedCookieMixin.java b/web/src/main/java/org/springframework/security/web/jackson2/SavedCookieMixin.java index 3859b3ae24..817972db15 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/SavedCookieMixin.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/SavedCookieMixin.java @@ -44,10 +44,8 @@ abstract class SavedCookieMixin { @JsonCreator SavedCookieMixin(@JsonProperty("name") String name, @JsonProperty("value") String value, - @JsonProperty("comment") String comment, @JsonProperty("domain") String domain, - @JsonProperty("maxAge") int maxAge, @JsonProperty("path") String path, - @JsonProperty("secure") boolean secure, @JsonProperty("version") int version) { - + @JsonProperty("domain") String domain, @JsonProperty("maxAge") int maxAge, + @JsonProperty("path") String path, @JsonProperty("secure") boolean secure) { } } diff --git a/web/src/main/java/org/springframework/security/web/savedrequest/SavedCookie.java b/web/src/main/java/org/springframework/security/web/savedrequest/SavedCookie.java index c4d6dbce33..5f55c16df9 100644 --- a/web/src/main/java/org/springframework/security/web/savedrequest/SavedCookie.java +++ b/web/src/main/java/org/springframework/security/web/savedrequest/SavedCookie.java @@ -35,8 +35,6 @@ public class SavedCookie implements Serializable { private final String value; - private final String comment; - private final String domain; private final int maxAge; @@ -45,28 +43,13 @@ public class SavedCookie implements Serializable { private final boolean secure; - private final int version; - - /** - * @deprecated use - * {@link org.springframework.security.web.savedrequest.SavedCookie#SavedCookie(String, String, String, int, String, boolean)} - * instead - */ - @Deprecated(forRemoval = true, since = "6.1") - public SavedCookie(String name, String value, String comment, String domain, int maxAge, String path, - boolean secure, int version) { + public SavedCookie(String name, String value, String domain, int maxAge, String path, boolean secure) { this.name = name; this.value = value; - this.comment = comment; this.domain = domain; this.maxAge = maxAge; this.path = path; this.secure = secure; - this.version = version; - } - - public SavedCookie(String name, String value, String domain, int maxAge, String path, boolean secure) { - this(name, value, null, domain, maxAge, path, secure, 0); } public SavedCookie(Cookie cookie) { @@ -82,11 +65,6 @@ public class SavedCookie implements Serializable { return this.value; } - @Deprecated(forRemoval = true, since = "6.1") - public String getComment() { - return this.comment; - } - public String getDomain() { return this.domain; } @@ -103,23 +81,14 @@ public class SavedCookie implements Serializable { return this.secure; } - @Deprecated(forRemoval = true, since = "6.1") - public int getVersion() { - return this.version; - } - public Cookie getCookie() { Cookie cookie = new Cookie(getName(), getValue()); - if (getComment() != null) { - cookie.setComment(getComment()); - } if (getDomain() != null) { cookie.setDomain(getDomain()); } if (getPath() != null) { cookie.setPath(getPath()); } - cookie.setVersion(getVersion()); cookie.setMaxAge(getMaxAge()); cookie.setSecure(isSecure()); return cookie; diff --git a/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java b/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java index ba399db5b1..ec541fa7bc 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java @@ -362,17 +362,6 @@ public class AbstractRememberMeServicesTests { assertThat(cookie.isHttpOnly()).isTrue(); } - // SEC-2791 - @Test - public void setCookieMaxAge1VersionSet() { - MockRememberMeServices services = new MockRememberMeServices(); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - services.setCookie(new String[] { "value" }, 1, request, response); - Cookie cookie = response.getCookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY); - assertThat(cookie.getVersion()).isZero(); - } - @Test public void setCookieDomainValue() { MockRememberMeServices services = new MockRememberMeServices(); diff --git a/web/src/test/java/org/springframework/security/web/firewall/FirewalledResponseTests.java b/web/src/test/java/org/springframework/security/web/firewall/FirewalledResponseTests.java index e5d7c03a4b..4db7f46b85 100644 --- a/web/src/test/java/org/springframework/security/web/firewall/FirewalledResponseTests.java +++ b/web/src/test/java/org/springframework/security/web/firewall/FirewalledResponseTests.java @@ -93,7 +93,6 @@ public class FirewalledResponseTests { Cookie cookie = new Cookie("foo", "bar"); cookie.setPath("/foobar"); cookie.setDomain("foobar"); - cookie.setComment("foobar"); this.fwResponse.addCookie(cookie); verify(this.response).addCookie(cookie); } diff --git a/web/src/test/java/org/springframework/security/web/jackson2/DefaultSavedRequestMixinTests.java b/web/src/test/java/org/springframework/security/web/jackson2/DefaultSavedRequestMixinTests.java index 6e7a8bc054..e290e06828 100644 --- a/web/src/test/java/org/springframework/security/web/jackson2/DefaultSavedRequestMixinTests.java +++ b/web/src/test/java/org/springframework/security/web/jackson2/DefaultSavedRequestMixinTests.java @@ -45,11 +45,9 @@ public class DefaultSavedRequestMixinTests extends AbstractMixinTests { + "\"@class\": \"org.springframework.security.web.savedrequest.SavedCookie\", " + "\"name\": \"SESSION\", " + "\"value\": \"123456789\", " - + "\"comment\": null, " + "\"maxAge\": -1, " + "\"path\": null, " + "\"secure\":false, " - + "\"version\": 0, " + "\"domain\": null" + "}]]"; // @formatter:on diff --git a/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java b/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java index 2582bddd9a..9374654d14 100644 --- a/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java +++ b/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java @@ -42,11 +42,9 @@ public class SavedCookieMixinTests extends AbstractMixinTests { + "\"@class\": \"org.springframework.security.web.savedrequest.SavedCookie\", " + "\"name\": \"SESSION\", " + "\"value\": \"123456789\", " - + "\"comment\": null, " + "\"maxAge\": -1, " + "\"path\": null, " + "\"secure\":false, " - + "\"version\": 0, " + "\"domain\": null" + "}"; // @formatter:on @@ -90,13 +88,11 @@ public class SavedCookieMixinTests extends AbstractMixinTests { @Test public void deserializeSavedCookieJsonTest() throws IOException { - SavedCookie savedCookie = (SavedCookie) this.mapper.readValue(COOKIE_JSON, Object.class); + SavedCookie savedCookie = this.mapper.readValue(COOKIE_JSON, SavedCookie.class); assertThat(savedCookie).isNotNull(); assertThat(savedCookie.getName()).isEqualTo("SESSION"); assertThat(savedCookie.getValue()).isEqualTo("123456789"); assertThat(savedCookie.isSecure()).isEqualTo(false); - assertThat(savedCookie.getVersion()).isZero(); - assertThat(savedCookie.getComment()).isNull(); } } diff --git a/web/src/test/java/org/springframework/security/web/savedrequest/SavedCookieTests.java b/web/src/test/java/org/springframework/security/web/savedrequest/SavedCookieTests.java index 77d0759657..9fdee451d4 100644 --- a/web/src/test/java/org/springframework/security/web/savedrequest/SavedCookieTests.java +++ b/web/src/test/java/org/springframework/security/web/savedrequest/SavedCookieTests.java @@ -33,12 +33,10 @@ public class SavedCookieTests { @BeforeEach public void setUp() { this.cookie = new Cookie("name", "value"); - this.cookie.setComment("comment"); this.cookie.setDomain("domain"); this.cookie.setMaxAge(100); this.cookie.setPath("path"); this.cookie.setSecure(true); - this.cookie.setVersion(11); this.savedCookie = new SavedCookie(this.cookie); } @@ -52,11 +50,6 @@ public class SavedCookieTests { assertThat(this.savedCookie.getValue()).isEqualTo(this.cookie.getValue()); } - @Test - public void testGetComment() { - assertThat(this.savedCookie.getComment()).isEqualTo(this.cookie.getComment()); - } - @Test public void testGetDomain() { assertThat(this.savedCookie.getDomain()).isEqualTo(this.cookie.getDomain()); @@ -72,22 +65,15 @@ public class SavedCookieTests { assertThat(this.savedCookie.getPath()).isEqualTo(this.cookie.getPath()); } - @Test - public void testGetVersion() { - assertThat(this.savedCookie.getVersion()).isEqualTo(this.cookie.getVersion()); - } - @Test public void testGetCookie() { Cookie other = this.savedCookie.getCookie(); - assertThat(other.getComment()).isEqualTo(this.cookie.getComment()); assertThat(other.getDomain()).isEqualTo(this.cookie.getDomain()); assertThat(other.getMaxAge()).isEqualTo(this.cookie.getMaxAge()); assertThat(other.getName()).isEqualTo(this.cookie.getName()); assertThat(other.getPath()).isEqualTo(this.cookie.getPath()); assertThat(other.getSecure()).isEqualTo(this.cookie.getSecure()); assertThat(other.getValue()).isEqualTo(this.cookie.getValue()); - assertThat(other.getVersion()).isEqualTo(this.cookie.getVersion()); } @Test From 6118587ff8f9879a2886194d8899ed6c84538a22 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 7 May 2025 14:38:09 -0500 Subject: [PATCH 188/504] SavedCookieMixinTests uses readValue(String,Object.class) The test should not provide SavedCookie.class to the ObjectMapper since this is not done in production. In particular, it provides the type that it should be deserialized, but this must be provided in the JSON since the type is unknown at the time of deserialization. Issue gh-17006 --- .../security/web/jackson2/SavedCookieMixinTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java b/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java index 9374654d14..1965146a11 100644 --- a/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java +++ b/web/src/test/java/org/springframework/security/web/jackson2/SavedCookieMixinTests.java @@ -88,7 +88,7 @@ public class SavedCookieMixinTests extends AbstractMixinTests { @Test public void deserializeSavedCookieJsonTest() throws IOException { - SavedCookie savedCookie = this.mapper.readValue(COOKIE_JSON, SavedCookie.class); + SavedCookie savedCookie = (SavedCookie) this.mapper.readValue(COOKIE_JSON, Object.class); assertThat(savedCookie).isNotNull(); assertThat(savedCookie.getName()).isEqualTo("SESSION"); assertThat(savedCookie.getValue()).isEqualTo("123456789"); From 1e4dd713c59814cc9c9252dcf39babcd0c502fc4 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 7 May 2025 23:35:54 +0700 Subject: [PATCH 189/504] Remove APPLICATION_JSON_UTF8 usage Signed-off-by: Tran Ngoc Nhan --- ...ultOAuth2TokenRequestHeadersConverter.java | 4 +- ...orizationCodeTokenResponseClientTests.java | 5 +-- ...ntCredentialsTokenResponseClientTests.java | 5 +-- ...aultJwtBearerTokenResponseClientTests.java | 5 +-- ...uth2TokenRequestHeadersConverterTests.java | 9 ++--- ...faultPasswordTokenResponseClientTests.java | 5 +-- ...tRefreshTokenTokenResponseClientTests.java | 5 +-- ...TokenExchangeTokenResponseClientTests.java | 14 +++---- ...earerGrantRequestEntityConverterTests.java | 5 +-- ...nCodeGrantRequestEntityConverterTests.java | 7 ++-- ...tialsGrantRequestEntityConverterTests.java | 7 ++-- ...swordGrantRequestEntityConverterTests.java | 5 +-- ...TokenGrantRequestEntityConverterTests.java | 5 +-- ...hangeGrantRequestEntityConverterTests.java | 8 ++-- .../security/http/MediaTypes.java | 39 ------------------- 15 files changed, 34 insertions(+), 94 deletions(-) delete mode 100644 web/src/main/java/org/springframework/security/http/MediaTypes.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java index c7bb26f91f..bcd2c1b19d 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -99,7 +98,6 @@ public final class DefaultOAuth2TokenRequestHeadersConverter DefaultOAuth2TokenRequestHeadersConverter withCharsetUtf8() { DefaultOAuth2TokenRequestHeadersConverter converter = new DefaultOAuth2TokenRequestHeadersConverter<>(); - converter.accept = List.of(MediaTypes.APPLICATION_JSON_UTF8); converter.contentType = APPLICATION_FORM_URLENCODED_UTF8; return converter; } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java index e285c61ff6..57cdd38b18 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultAuthorizationCodeTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -119,7 +118,7 @@ public class DefaultAuthorizationCodeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java index d175bcf22b..96c6de171c 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultClientCredentialsTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -122,7 +121,7 @@ public class DefaultClientCredentialsTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java index a00a9b0090..d2a95f6418 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultJwtBearerTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -116,7 +115,7 @@ public class DefaultJwtBearerTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverterTests.java index 2ba7888ecd..f264679796 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,9 +35,6 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class DefaultOAuth2TokenRequestHeadersConverterTests { - private static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON, - StandardCharsets.UTF_8); - private static final MediaType APPLICATION_FORM_URLENCODED_UTF8 = new MediaType( MediaType.APPLICATION_FORM_URLENCODED, StandardCharsets.UTF_8); @@ -92,7 +89,7 @@ public class DefaultOAuth2TokenRequestHeadersConverterTests { // @formatter:on OAuth2ClientCredentialsGrantRequest grantRequest = new OAuth2ClientCredentialsGrantRequest(clientRegistration); HttpHeaders defaultHeaders = this.converter.convert(grantRequest); - assertThat(defaultHeaders.getAccept()).containsExactly(APPLICATION_JSON_UTF8); + assertThat(defaultHeaders.getAccept()).containsExactly(MediaType.APPLICATION_JSON); assertThat(defaultHeaders.getContentType()).isEqualTo(APPLICATION_FORM_URLENCODED_UTF8); assertThat(defaultHeaders.getFirst(HttpHeaders.AUTHORIZATION)) .isEqualTo("Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0JTNE"); @@ -110,7 +107,7 @@ public class DefaultOAuth2TokenRequestHeadersConverterTests { // @formatter:on OAuth2ClientCredentialsGrantRequest grantRequest = new OAuth2ClientCredentialsGrantRequest(clientRegistration); HttpHeaders defaultHeaders = this.converter.convert(grantRequest); - assertThat(defaultHeaders.getAccept()).containsExactly(APPLICATION_JSON_UTF8); + assertThat(defaultHeaders.getAccept()).containsExactly(MediaType.APPLICATION_JSON); assertThat(defaultHeaders.getContentType()).isEqualTo(APPLICATION_FORM_URLENCODED_UTF8); assertThat(defaultHeaders.getFirst(HttpHeaders.AUTHORIZATION)) .isEqualTo("Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0PQ=="); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java index a33b234e64..62ea7dc2c3 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultPasswordTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -116,7 +115,7 @@ public class DefaultPasswordTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java index 61c4f2d2de..c1ee06fcd3 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultRefreshTokenTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,6 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -118,7 +117,7 @@ public class DefaultRefreshTokenTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaTypes.APPLICATION_JSON_UTF8_VALUE); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); assertThat(recordedRequest.getHeader(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClientTests.java index 9624c6465c..4d0afc9163 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/DefaultTokenExchangeTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,8 +149,7 @@ public class DefaultTokenExchangeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)) - .isEqualTo(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); @@ -189,8 +188,7 @@ public class DefaultTokenExchangeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)) - .isEqualTo(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); @@ -229,8 +227,7 @@ public class DefaultTokenExchangeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)) - .isEqualTo(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); @@ -271,8 +268,7 @@ public class DefaultTokenExchangeTokenResponseClientTests { Instant expiresAtAfter = Instant.now().plusSeconds(3600); RecordedRequest recordedRequest = this.server.takeRequest(); assertThat(recordedRequest.getMethod()).isEqualTo(HttpMethod.POST.toString()); - assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)) - .isEqualTo(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"); + assertThat(recordedRequest.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"); String formParameters = recordedRequest.getBody().readUtf8(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java index 88d06285b2..d228e2bd8a 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/JwtBearerGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -135,7 +134,7 @@ public class JwtBearerGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaType.valueOf(MediaTypes.APPLICATION_JSON_UTF8_VALUE)); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java index ac824a681d..a90201938b 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2AuthorizationCodeGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -139,7 +138,7 @@ public class OAuth2AuthorizationCodeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0JTNE"); @@ -178,7 +177,7 @@ public class OAuth2AuthorizationCodeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).isNull(); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java index af25ccb9f1..91d9e36c1c 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2ClientCredentialsGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -124,7 +123,7 @@ public class OAuth2ClientCredentialsGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); @@ -153,7 +152,7 @@ public class OAuth2ClientCredentialsGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); String urlEncodedClientCredential = URLEncoder.encode(clientCredentialWithAnsiKeyboardSpecialCharacters, diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java index 5a6a8811e8..a9de0ceba7 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2PasswordGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -119,7 +118,7 @@ public class OAuth2PasswordGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java index fee0e2b02c..959b92fbb0 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/OAuth2RefreshTokenGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; -import org.springframework.security.http.MediaTypes; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -131,7 +130,7 @@ public class OAuth2RefreshTokenGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()).contains(MediaTypes.APPLICATION_JSON_UTF8); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverterTests.java index 8a77a66dfb..38c2c29e6f 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/TokenExchangeGrantRequestEntityConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -161,8 +161,7 @@ public class TokenExchangeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()) - .contains(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8")); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).startsWith("Basic "); @@ -197,8 +196,7 @@ public class TokenExchangeGrantRequestEntityConverterTests { assertThat(requestEntity.getUrl().toASCIIString()) .isEqualTo(clientRegistration.getProviderDetails().getTokenUri()); HttpHeaders headers = requestEntity.getHeaders(); - assertThat(headers.getAccept()) - .contains(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8")); + assertThat(headers.getAccept()).contains(MediaType.APPLICATION_JSON); assertThat(headers.getContentType()) .isEqualTo(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION)).isNull(); diff --git a/web/src/main/java/org/springframework/security/http/MediaTypes.java b/web/src/main/java/org/springframework/security/http/MediaTypes.java deleted file mode 100644 index 96b6c2d989..0000000000 --- a/web/src/main/java/org/springframework/security/http/MediaTypes.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.http; - -import java.nio.charset.StandardCharsets; - -import org.springframework.http.MediaType; - -/** - * This is a placeholder to allow an incremental update to Spring Framework 7.0. - * - * @deprecated For removal - */ -@Deprecated(since = "7.0.0", forRemoval = true) -public final class MediaTypes { - - public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON, - StandardCharsets.UTF_8); - - public static final String APPLICATION_JSON_UTF8_VALUE = APPLICATION_JSON_UTF8.toString(); - - private MediaTypes() { - } - -} From 48eb2430127d074459fe9f149de51e0288f10885 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 7 May 2025 23:41:30 +0700 Subject: [PATCH 190/504] Update javadoc Signed-off-by: Tran Ngoc Nhan --- .../endpoint/DefaultOAuth2TokenRequestHeadersConverter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java index bcd2c1b19d..40419e1143 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/DefaultOAuth2TokenRequestHeadersConverter.java @@ -91,8 +91,8 @@ public final class DefaultOAuth2TokenRequestHeadersConverter Date: Wed, 7 May 2025 14:09:23 -0400 Subject: [PATCH 191/504] Add documentation for DPoP support Closes gh-17072 --- .../DPoPAuthenticationConfigurer.java | 5 + docs/modules/ROOT/nav.adoc | 1 + .../oauth2/resource-server/dpop-tokens.adoc | 212 ++++++++++++++++++ docs/modules/ROOT/pages/whats-new.adoc | 1 + .../security/oauth2/jwt/DPoPProofContext.java | 57 +++++ .../jwt/DPoPProofJwtDecoderFactory.java | 24 +- .../DPoPAuthenticationProvider.java | 17 ++ .../DPoPAuthenticationToken.java | 30 +++ 8 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 docs/modules/ROOT/pages/servlet/oauth2/resource-server/dpop-tokens.adoc diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java index b433602e5a..cee89e0427 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java @@ -53,9 +53,14 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** + * An {@link AbstractHttpConfigurer} for OAuth 2.0 Demonstrating Proof of Possession + * (DPoP) support. + * * @author Joe Grandja * @since 6.5 * @see DPoPAuthenticationProvider + * @see RFC 9449 + * OAuth 2.0 Demonstrating Proof of Possession (DPoP) */ final class DPoPAuthenticationConfigurer> extends AbstractHttpConfigurer, B> { diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index d65fc977c0..e871974c12 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -82,6 +82,7 @@ **** xref:servlet/oauth2/resource-server/opaque-token.adoc[Opaque Token] **** xref:servlet/oauth2/resource-server/multitenancy.adoc[Multitenancy] **** xref:servlet/oauth2/resource-server/bearer-tokens.adoc[Bearer Tokens] +**** xref:servlet/oauth2/resource-server/dpop-tokens.adoc[DPoP-bound Access Tokens] ** xref:servlet/saml2/index.adoc[SAML2] *** xref:servlet/saml2/login/index.adoc[SAML2 Log In] **** xref:servlet/saml2/login/overview.adoc[SAML2 Log In Overview] diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/dpop-tokens.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/dpop-tokens.adoc new file mode 100644 index 0000000000..bf749baa72 --- /dev/null +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/dpop-tokens.adoc @@ -0,0 +1,212 @@ +[[oauth2-dpop-bound-access-tokens]] += OAuth 2.0 DPoP-bound Access Tokens + +https://datatracker.ietf.org/doc/html/rfc9449[RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP)] is an application-level mechanism for sender-constraining an access token. + +The primary goal of DPoP is to prevent unauthorized or illegitimate clients from using leaked or stolen access tokens, by binding an access token to a public key upon issuance by the authorization server and requiring that the client proves possession of the corresponding private key when using the access token at the resource server. + +Access tokens that are sender-constrained via DPoP stand in contrast to the typical bearer token, which can be used by any client in possession of the access token. + +DPoP introduces the concept of a https://datatracker.ietf.org/doc/html/rfc9449#name-dpop-proof-jwts[DPoP Proof], which is a JWT created by the client and sent as a header in an HTTP request. +A client uses a DPoP proof to prove the possession of a private key corresponding to a certain public key. + +When the client initiates an <>, it attaches a DPoP proof to the request in an HTTP header. +The authorization server binds (sender-constrains) the access token to the public key associated in the DPoP proof. + +When the client initiates a <>, it again attaches a DPoP proof to the request in an HTTP header. + +The resource server obtains information about the public key bound to the access token, either directly in the access token (JWT) or via the token introspection endpoint. +The resource server then verifies that the public key bound to the access token matches the public key in the DPoP proof. +It also verifies that the access token hash in the DPoP proof matches the access token in the request. + +[[dpop-access-token-request]] +== DPoP Access Token Request + +To request an access token that is bound to a public key using DPoP, the client MUST provide a valid DPoP proof in the `DPoP` header when making an access token request to the authorization server token endpoint. +This is applicable for all access token requests regardless of authorization grant type (e.g. `authorization_code`, `refresh_token`, `client_credentials`, etc). + +The following HTTP request shows an `authorization_code` access token request with a DPoP proof in the `DPoP` header: + +[source,shell] +---- +POST /oauth2/token HTTP/1.1 +Host: server.example.com +Content-Type: application/x-www-form-urlencoded +DPoP: eyJraWQiOiJyc2EtandrLWtpZCIsInR5cCI6ImRwb3Arand0IiwiYWxnIjoiUlMyNTYiLCJqd2siOnsia3R5IjoiUlNBIiwiZSI6IkFRQUIiLCJraWQiOiJyc2EtandrLWtpZCIsIm4iOiIzRmxxSnI1VFJza0lRSWdkRTNEZDdEOWxib1dkY1RVVDhhLWZKUjdNQXZRbTdYWE5vWWttM3Y3TVFMMU5ZdER2TDJsOENBbmMwV2RTVElOVTZJUnZjNUtxbzJRNGNzTlg5U0hPbUVmem9ST2pRcWFoRWN2ZTFqQlhsdW9DWGRZdVlweDRfMXRmUmdHNmlpNFVoeGg2aUk4cU5NSlFYLWZMZnFoYmZZZnhCUVZSUHl3QmtBYklQNHgxRUFzYkM2RlNObWtoQ3hpTU5xRWd4YUlwWThDMmtKZEpfWklWLVdXNG5vRGR6cEtxSGN3bUI4RnNydW1sVllfRE5WdlVTRElpcGlxOVBiUDRIOTlUWE4xbzc0Nm9SYU5hMDdycTFob0NnTVNTeS04NVNhZ0NveGxteUUtRC1vZjlTc01ZOE9sOXQwcmR6cG9iQnVoeUpfbzVkZnZqS3cifX0.eyJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vb2F1dGgyL3Rva2VuIiwiaWF0IjoxNzQ2ODA2MzA1LCJqdGkiOiI0YjIzNDBkMi1hOTFmLTQwYTUtYmFhOS1kZDRlNWRlYWM4NjcifQ.wq8gJ_G6vpiEinfaY3WhereqCCLoeJOG8tnWBBAzRWx9F1KU5yAAWq-ZVCk_k07-h6DIqz2wgv6y9dVbNpRYwNwDUeik9qLRsC60M8YW7EFVyI3n_NpujLwzZeub_nDYMVnyn4ii0NaZrYHtoGXOlswQfS_-ET-jpC0XWm5nBZsCdUEXjOYtwaACC6Js-pyNwKmSLp5SKIk11jZUR5xIIopaQy521y9qJHhGRwzj8DQGsP7wMZ98UFL0E--1c-hh4rTy8PMeWCqRHdwjj_ry_eTe0DJFcxxYQdeL7-0_0CIO4Ayx5WHEpcUOIzBRoN32RsNpDZc-5slDNj9ku004DA + +grant_type=authorization_code\ +&client_id=s6BhdRkqt\ +&code=SplxlOBeZQQYbYS6WxSbIA\ +&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\ +&code_verifier=bEaL42izcC-o-xBk0K2vuJ6U-y1p9r_wW2dFWIWgjz- +---- + +The following shows a representation of the DPoP Proof JWT header and claims: + +[source,json] +---- +{ + "typ": "dpop+jwt", + "alg": "RS256", + "jwk": { + "kty": "RSA", + "e": "AQAB", + "n": "3FlqJr5TRskIQIgdE3Dd7D9lboWdcTUT8a-fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRvc5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4_1tfRgG6ii4Uhxh6iI8qNMJQX-fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2kJdJ_ZIV-WW4noDdzpKqHcwmB8FsrumlVY_DNVvUSDIipiq9PbP4H99TXN1o746oRaNa07rq1hoCgMSSy-85SagCoxlmyE-D-of9SsMY8Ol9t0rdzpobBuhyJ_o5dfvjKw" + } +} +---- + +[source,json] +---- +{ + "htm": "POST", + "htu": "https://server.example.com/oauth2/token", + "iat": 1746806305, + "jti": "4b2340d2-a91f-40a5-baa9-dd4e5deac867" +} +---- + +The following code shows an example of how to generate the DPoP Proof JWT: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +RSAKey rsaKey = ... +JWKSource jwkSource = (jwkSelector, securityContext) -> jwkSelector + .select(new JWKSet(rsaKey)); +NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource); + +JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.RS256) + .type("dpop+jwt") + .jwk(rsaKey.toPublicJWK().toJSONObject()) + .build(); +JwtClaimsSet claims = JwtClaimsSet.builder() + .issuedAt(Instant.now()) + .claim("htm", "POST") + .claim("htu", "https://server.example.com/oauth2/token") + .id(UUID.randomUUID().toString()) + .build(); + +Jwt dPoPProof = jwtEncoder.encode(JwtEncoderParameters.from(jwsHeader, claims)); +---- +====== + +After the authorization server successfully validates the DPoP proof, the public key from the DPoP proof will be bound (sender-constrained) to the issued access token. + +The following access token response shows the `token_type` parameter as `DPoP` to signal to the client that the access token was bound to its DPoP proof public key: + +[source,shell] +---- +HTTP/1.1 200 OK +Content-Type: application/json +Cache-Control: no-store + +{ + "access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU", + "token_type": "DPoP", + "expires_in": 2677 +} +---- + +[[dpop-public-key-confirmation]] +== Public Key Confirmation + +Resource servers MUST be able to identify whether an access token is DPoP-bound and verify the binding to the public key of the DPoP proof. +The binding is accomplished by associating the public key with the access token in a way that can be accessed by the resource server, such as embedding the public key hash in the access token directly (JWT) or through token introspection. + +When an access token is represented as a JWT, the public key hash is contained in the `jkt` claim under the confirmation method (`cnf`) claim. + +The following example shows the claims of a JWT access token containing a `cnf` claim with a `jkt` claim, which is the JWK SHA-256 Thumbprint of the DPoP proof public key: + +[source,json] +---- +{ + "sub":"user@example.com", + "iss":"https://server.example.com", + "nbf":1562262611, + "exp":1562266216, + "cnf": + { + "jkt":"CQMknzRoZ5YUi7vS58jck1q8TmZT8wiIiXrCN1Ny4VU" + } +} +---- + +[[dpop-protected-resource-request]] +== DPoP Protected Resource Request + +Requests to DPoP-protected resources MUST include both a DPoP proof and the DPoP-bound access token. +The DPoP proof MUST include the `ath` claim with a valid hash of the access token. +The resource server will calculate the hash of the received access token and verify that it is the same as the `ath` claim in the DPoP proof. + +A DPoP-bound access token is sent using the `Authorization` request header with an authentication scheme of `DPoP`. + +The following HTTP request shows a protected resource request with a DPoP-bound access token in the `Authorization` header and the DPoP proof in the `DPoP` header: + +[source,shell] +---- +GET /resource HTTP/1.1 +Host: resource.example.com +Authorization: DPoP Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU +DPoP: eyJraWQiOiJyc2EtandrLWtpZCIsInR5cCI6ImRwb3Arand0IiwiYWxnIjoiUlMyNTYiLCJqd2siOnsia3R5IjoiUlNBIiwiZSI6IkFRQUIiLCJraWQiOiJyc2EtandrLWtpZCIsIm4iOiIzRmxxSnI1VFJza0lRSWdkRTNEZDdEOWxib1dkY1RVVDhhLWZKUjdNQXZRbTdYWE5vWWttM3Y3TVFMMU5ZdER2TDJsOENBbmMwV2RTVElOVTZJUnZjNUtxbzJRNGNzTlg5U0hPbUVmem9ST2pRcWFoRWN2ZTFqQlhsdW9DWGRZdVlweDRfMXRmUmdHNmlpNFVoeGg2aUk4cU5NSlFYLWZMZnFoYmZZZnhCUVZSUHl3QmtBYklQNHgxRUFzYkM2RlNObWtoQ3hpTU5xRWd4YUlwWThDMmtKZEpfWklWLVdXNG5vRGR6cEtxSGN3bUI4RnNydW1sVllfRE5WdlVTRElpcGlxOVBiUDRIOTlUWE4xbzc0Nm9SYU5hMDdycTFob0NnTVNTeS04NVNhZ0NveGxteUUtRC1vZjlTc01ZOE9sOXQwcmR6cG9iQnVoeUpfbzVkZnZqS3cifX0.eyJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUuY29tL3Jlc291cmNlIiwiYXRoIjoiZlVIeU8ycjJaM0RaNTNFc05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyIsImlhdCI6MTc0NjgwNzEzOCwianRpIjoiM2MyZWU5YmItMDNhYy00MGNmLWI4MTItMDBiZmJhMzQxY2VlIn0.oS6NwjURR6wZemh1ZBNiBjycGeXwnkguLtgiKdCjQSEhFQpEJm04bBa0tdfZgWT17Z2mBgddnNQSkROzUGfssg8rBBldZXOAiduF-whtEGZA-pXXWJilXrwH3Glb6hIOMZOVmIH8fmYCDmqn-sE_DmDIsv57Il2-jdZbgeDcrxADO-6E5gsuNf1jvy7qqHq7INrKX6jRuydti_Re35lecvaAWfTyD7s7tQ_-3x_xLxxPwf_eA6z8OWbc58O2PYoUeO2JKLiOIg6UVZOZzxLEWV42WIKjha_kkoykvsf98W2y8pWOEr65u0VPsn5esw2X3I1eFL_A-XkxstZHRaGXJg +---- + +The following shows a representation of the DPoP Proof JWT header and claims with the `ath` claim: + +[source,json] +---- +{ + "typ": "dpop+jwt", + "alg": "RS256", + "jwk": { + "kty": "RSA", + "e": "AQAB", + "n": "3FlqJr5TRskIQIgdE3Dd7D9lboWdcTUT8a-fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRvc5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4_1tfRgG6ii4Uhxh6iI8qNMJQX-fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2kJdJ_ZIV-WW4noDdzpKqHcwmB8FsrumlVY_DNVvUSDIipiq9PbP4H99TXN1o746oRaNa07rq1hoCgMSSy-85SagCoxlmyE-D-of9SsMY8Ol9t0rdzpobBuhyJ_o5dfvjKw" + } +} +---- + +[source,json] +---- +{ + "htm": "GET", + "htu": "https://resource.example.com/resource", + "ath": "fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo", + "iat": 1746807138, + "jti": "3c2ee9bb-03ac-40cf-b812-00bfba341cee" +} +---- + +The following code shows an example of how to generate the DPoP Proof JWT: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +RSAKey rsaKey = ... +JWKSource jwkSource = (jwkSelector, securityContext) -> jwkSelector + .select(new JWKSet(rsaKey)); +NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource); + +String accessToken = ... + +JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.RS256) + .type("dpop+jwt") + .jwk(rsaKey.toPublicJWK().toJSONObject()) + .build(); +JwtClaimsSet claims = JwtClaimsSet.builder() + .issuedAt(Instant.now()) + .claim("htm", "GET") + .claim("htu", "https://resource.example.com/resource") + .claim("ath", sha256(accessToken)) + .id(UUID.randomUUID().toString()) + .build(); + +Jwt dPoPProof = jwtEncoder.encode(JwtEncoderParameters.from(jwsHeader, claims)); +---- +====== diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index b1bc5f72b1..a75c999dd4 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -7,6 +7,7 @@ Below are the highlights of the release, or you can view https://github.com/spri == New Features * Support for automatic context-propagation with Micrometer (https://github.com/spring-projects/spring-security/issues/16665[gh-16665]) +* OAuth 2.0 Demonstrating Proof of Possession (DPoP) (https://github.com/spring-projects/spring-security/pull/16574[gh-16574]) == Breaking Changes diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java index 16a5947cf5..3a3fac8124 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofContext.java @@ -23,6 +23,9 @@ import org.springframework.security.oauth2.core.OAuth2Token; import org.springframework.util.Assert; /** + * A context class that holds a DPoP Proof {@link Jwt} and additional parameters + * associated to an Access Token request or a Protected Resource request. + * * @author Joe Grandja * @since 6.5 * @see DPoPProofJwtDecoderFactory @@ -44,28 +47,58 @@ public final class DPoPProofContext { this.accessToken = accessToken; } + /** + * Returns the DPoP Proof {@link Jwt}. + * @return the DPoP Proof {@link Jwt} + */ public String getDPoPProof() { return this.dPoPProof; } + /** + * Returns the value of the HTTP method of the request to which the DPoP Proof + * {@link Jwt} is attached. + * @return the value of the HTTP method of the request to which the DPoP Proof + * {@link Jwt} is attached + */ public String getMethod() { return this.method; } + /** + * Returns the value of the HTTP target URI of the request to which the DPoP Proof + * {@link Jwt} is attached, without query and fragment parts. + * @return the value of the HTTP target URI of the request to which the DPoP Proof + * {@link Jwt} is attached + */ public String getTargetUri() { return this.targetUri; } + /** + * Returns the access token if the request is a Protected Resource request. + * @param the type of the access token + * @return the access token if the request is a Protected Resource request or + * {@code null} + */ @SuppressWarnings("unchecked") @Nullable public T getAccessToken() { return (T) this.accessToken; } + /** + * Returns a new {@link Builder}, initialized with the DPoP Proof {@link Jwt}. + * @param dPoPProof the DPoP Proof {@link Jwt} + * @return the {@link Builder} + */ public static Builder withDPoPProof(String dPoPProof) { return new Builder(dPoPProof); } + /** + * A builder for {@link DPoPProofContext}. + */ public static final class Builder { private String dPoPProof; @@ -81,21 +114,45 @@ public final class DPoPProofContext { this.dPoPProof = dPoPProof; } + /** + * Sets the value of the HTTP method of the request to which the DPoP Proof + * {@link Jwt} is attached. + * @param method the value of the HTTP method of the request to which the DPoP + * Proof {@link Jwt} is attached + * @return the {@link Builder} + */ public Builder method(String method) { this.method = method; return this; } + /** + * Sets the value of the HTTP target URI of the request to which the DPoP Proof + * {@link Jwt} is attached, without query and fragment parts. + * @param targetUri the value of the HTTP target URI of the request to which the + * DPoP Proof {@link Jwt} is attached + * @return the {@link Builder} + */ public Builder targetUri(String targetUri) { this.targetUri = targetUri; return this; } + /** + * Sets the access token if the request is a Protected Resource request. + * @param accessToken the access token if the request is a Protected Resource + * request + * @return the {@link Builder} + */ public Builder accessToken(OAuth2Token accessToken) { this.accessToken = accessToken; return this; } + /** + * Builds a new {@link DPoPProofContext}. + * @return a {@link DPoPProofContext} + */ public DPoPProofContext build() { validate(); return new DPoPProofContext(this.dPoPProof, this.method, this.targetUri, this.accessToken); diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java index 9b27313e37..509d0d25eb 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java @@ -48,17 +48,29 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** + * A {@link JwtDecoderFactory factory} that provides a {@link JwtDecoder} for the + * specified {@link DPoPProofContext} and is used for authenticating a DPoP Proof + * {@link Jwt}. + * * @author Joe Grandja * @since 6.5 + * @see JwtDecoderFactory * @see DPoPProofContext + * @see RFC 9449 + * OAuth 2.0 Demonstrating Proof of Possession (DPoP) */ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory { + /** + * The default {@code OAuth2TokenValidator} factory that validates the + * {@code htm}, {@code htu}, {@code jti} and {@code iat} claims of the DPoP Proof + * {@link Jwt}. + */ + public static final Function> DEFAULT_JWT_VALIDATOR_FACTORY = defaultJwtValidatorFactory(); + private static final JOSEObjectTypeVerifier DPOP_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier<>( new JOSEObjectType("dpop+jwt")); - public static final Function> DEFAULT_JWT_VALIDATOR_FACTORY = defaultJwtValidatorFactory(); - private Function> jwtValidatorFactory = DEFAULT_JWT_VALIDATOR_FACTORY; @Override @@ -69,6 +81,14 @@ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory} factory is + * {@link #DEFAULT_JWT_VALIDATOR_FACTORY}. + * @param jwtValidatorFactory the factory that provides an + * {@link OAuth2TokenValidator} for the specified {@link DPoPProofContext} + */ public void setJwtValidatorFactory(Function> jwtValidatorFactory) { Assert.notNull(jwtValidatorFactory, "jwtValidatorFactory cannot be null"); this.jwtValidatorFactory = jwtValidatorFactory; diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index b26cb754c7..32d7b09fa1 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -50,10 +50,15 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** + * An {@link AuthenticationProvider} implementation that is responsible for authenticating + * a DPoP-bound access token for a protected resource request. + * * @author Joe Grandja * @since 6.5 * @see DPoPAuthenticationToken * @see DPoPProofJwtDecoderFactory + * @see RFC 9449 + * OAuth 2.0 Demonstrating Proof of Possession (DPoP) */ public final class DPoPAuthenticationProvider implements AuthenticationProvider { @@ -61,6 +66,11 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider private JwtDecoderFactory dPoPProofVerifierFactory; + /** + * Constructs a {@code DPoPAuthenticationProvider} using the provided parameters. + * @param tokenAuthenticationManager the {@link AuthenticationManager} used to + * authenticate the DPoP-bound access token + */ public DPoPAuthenticationProvider(AuthenticationManager tokenAuthenticationManager) { Assert.notNull(tokenAuthenticationManager, "tokenAuthenticationManager cannot be null"); this.tokenAuthenticationManager = tokenAuthenticationManager; @@ -121,6 +131,13 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return DPoPAuthenticationToken.class.isAssignableFrom(authentication); } + /** + * Sets the {@link JwtDecoderFactory} that provides a {@link JwtDecoder} for the + * specified {@link DPoPProofContext} and is used for authenticating a DPoP Proof + * {@link Jwt}. The default factory is {@link DPoPProofJwtDecoderFactory}. + * @param dPoPProofVerifierFactory the {@link JwtDecoderFactory} that provides a + * {@link JwtDecoder} for the specified {@link DPoPProofContext} + */ public void setDPoPProofVerifierFactory(JwtDecoderFactory dPoPProofVerifierFactory) { Assert.notNull(dPoPProofVerifierFactory, "dPoPProofVerifierFactory cannot be null"); this.dPoPProofVerifierFactory = dPoPProofVerifierFactory; diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationToken.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationToken.java index 0abca69706..35593d8361 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationToken.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationToken.java @@ -20,9 +20,14 @@ import java.io.Serial; import java.util.Collections; import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.util.Assert; /** + * An {@link Authentication} representing a protected resource request with a DPoP-bound + * access token. + * * @author Joe Grandja * @since 6.5 * @see DPoPAuthenticationProvider @@ -40,6 +45,14 @@ public class DPoPAuthenticationToken extends AbstractAuthenticationToken { private final String resourceUri; + /** + * Constructs a {@code DPoPAuthenticationToken} using the provided parameters. + * @param accessToken the DPoP-bound access token + * @param dPoPProof the DPoP Proof {@link Jwt} + * @param method the value of the HTTP method of the request + * @param resourceUri the value of the HTTP resource URI of the request, without query + * and fragment parts + */ public DPoPAuthenticationToken(String accessToken, String dPoPProof, String method, String resourceUri) { super(Collections.emptyList()); Assert.hasText(accessToken, "accessToken cannot be empty"); @@ -62,18 +75,35 @@ public class DPoPAuthenticationToken extends AbstractAuthenticationToken { return getAccessToken(); } + /** + * Returns the DPoP-bound access token. + * @return the DPoP-bound access token + */ public String getAccessToken() { return this.accessToken; } + /** + * Returns the DPoP Proof {@link Jwt}. + * @return the DPoP Proof {@link Jwt} + */ public String getDPoPProof() { return this.dPoPProof; } + /** + * Returns the value of the HTTP method of the request. + * @return the value of the HTTP method of the request + */ public String getMethod() { return this.method; } + /** + * Returns the value of the HTTP resource URI of the request, without query and + * fragment parts. + * @return the value of the HTTP resource URI of the request + */ public String getResourceUri() { return this.resourceUri; } From a90ce5142cca8939a5267ea67b8d1efc8882aca8 Mon Sep 17 00:00:00 2001 From: yybmion Date: Fri, 25 Apr 2025 02:26:48 +0900 Subject: [PATCH 192/504] Add logging to CsrfTokenRequestHandler implementations Add trace-level logging to show the logical path of CSRF token processing - Log token source (header or parameter) in resolveCsrfTokenValue - Log request attribute names in handle methods - Log failures in XorCsrfTokenRequestAttributeHandler (especially Base64 decoding) - Add similar logging to XorServerCsrfTokenRequestAttributeHandler Improves debugging capabilities without changing functionality. Closes gh-13626 Signed-off-by: yybmion --- .../security/web/csrf/CsrfFilter.java | 3 ++ .../CsrfTokenRequestAttributeHandler.java | 11 ++++++- .../web/csrf/CsrfTokenRequestHandler.java | 20 +++++++++--- .../CsrfTokenRequestHandlerLoggerHolder.java | 32 +++++++++++++++++++ .../XorCsrfTokenRequestAttributeHandler.java | 15 ++++++++- ...erverCsrfTokenRequestAttributeHandler.java | 9 +++++- .../csrf/ServerCsrfTokenRequestHandler.java | 25 +++++++++++++-- ...erCsrfTokenRequestHandlerLoggerHolder.java | 32 +++++++++++++++++++ ...erverCsrfTokenRequestAttributeHandler.java | 12 ++++++- 9 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java create mode 100644 web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java index 2164675c74..f2e52554d0 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java @@ -119,6 +119,9 @@ public final class CsrfFilter extends OncePerRequestFilter { } CsrfToken csrfToken = deferredCsrfToken.get(); String actualToken = this.requestHandler.resolveCsrfTokenValue(request, csrfToken); + if (actualToken != null && this.logger.isTraceEnabled()) { + this.logger.trace(LogMessage.format("Found a CSRF token in the request")); + } if (!equalsConstantTime(csrfToken.getToken(), actualToken)) { boolean missingToken = deferredCsrfToken.isGenerated(); this.logger diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java index a0950fa44b..7e9a124c4d 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,10 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; /** @@ -29,10 +32,13 @@ import org.springframework.util.Assert; * value as either a header or parameter value of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public class CsrfTokenRequestAttributeHandler implements CsrfTokenRequestHandler { + private static final Log logger = LogFactory.getLog(CsrfTokenRequestAttributeHandler.class); + private String csrfRequestAttributeName = "_csrf"; /** @@ -60,6 +66,9 @@ public class CsrfTokenRequestAttributeHandler implements CsrfTokenRequestHandler String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName : csrfToken.getParameterName(); request.setAttribute(csrfAttrName, csrfToken); + + logger.trace(LogMessage.format("Wrote a CSRF token to the following request attributes: [%s, %s]", csrfAttrName, + CsrfToken.class.getName())); } @SuppressWarnings("serial") diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java index cbdf7d76dc..320c556faf 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; /** @@ -30,6 +31,7 @@ import org.springframework.util.Assert; * available to the application through request attributes. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 * @see CsrfTokenRequestAttributeHandler */ @@ -49,10 +51,20 @@ public interface CsrfTokenRequestHandler extends CsrfTokenRequestResolver { Assert.notNull(request, "request cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); String actualToken = request.getHeader(csrfToken.getHeaderName()); - if (actualToken == null) { - actualToken = request.getParameter(csrfToken.getParameterName()); + if (actualToken != null) { + return actualToken; } - return actualToken; + CsrfTokenRequestHandlerLoggerHolder.logger.trace( + LogMessage.format("Did not find a CSRF token in the [%s] request header", csrfToken.getHeaderName())); + + actualToken = request.getParameter(csrfToken.getParameterName()); + if (actualToken != null) { + return actualToken; + } + CsrfTokenRequestHandlerLoggerHolder.logger.trace(LogMessage + .format("Did not find a CSRF token in the [%s] request parameter", csrfToken.getParameterName())); + + return null; } } diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java new file mode 100644 index 0000000000..d90f675b56 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.csrf; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utility class for holding the logger for {@link CsrfTokenRequestHandler} + */ +final class CsrfTokenRequestHandlerLoggerHolder { + + static final Log logger = LogFactory.getLog(CsrfTokenRequestHandler.class); + + private CsrfTokenRequestHandlerLoggerHolder() { + } + +} diff --git a/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java index 9416d233eb..a59920e83f 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,10 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.log.LogMessage; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; @@ -32,10 +35,13 @@ import org.springframework.util.Assert; * value from the masked value as either a header or parameter value of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestAttributeHandler { + private static final Log logger = LogFactory.getLog(XorCsrfTokenRequestAttributeHandler.class); + private SecureRandom secureRandom = new SecureRandom(); /** @@ -70,6 +76,9 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA @Override public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { String actualToken = super.resolveCsrfTokenValue(request, csrfToken); + if (actualToken == null) { + return null; + } return getTokenValue(actualToken, csrfToken.getToken()); } @@ -79,12 +88,16 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA actualBytes = Base64.getUrlDecoder().decode(actualToken); } catch (Exception ex) { + logger.trace(LogMessage.format("Not returning the CSRF token since it's not Base64-encoded"), ex); return null; } byte[] tokenBytes = Utf8.encode(token); int tokenSize = tokenBytes.length; if (actualBytes.length != tokenSize * 2) { + logger.trace(LogMessage.format( + "Not returning the CSRF token since its Base64-decoded length (%d) is not equal to (%d)", + actualBytes.length, tokenSize * 2)); return null; } diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java index 888239d522..949c54ab06 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,11 @@ package org.springframework.security.web.server.csrf; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.codec.multipart.FormFieldPart; @@ -31,10 +34,13 @@ import org.springframework.web.server.ServerWebExchange; * resolving the token value as either a form data value or header of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public class ServerCsrfTokenRequestAttributeHandler implements ServerCsrfTokenRequestHandler { + private static final Log logger = LogFactory.getLog(ServerCsrfTokenRequestAttributeHandler.class); + private boolean isTokenFromMultipartDataEnabled; @Override @@ -42,6 +48,7 @@ public class ServerCsrfTokenRequestAttributeHandler implements ServerCsrfTokenRe Assert.notNull(exchange, "exchange cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken); + logger.trace(LogMessage.format("Wrote a CSRF token to the [%s] exchange attribute", CsrfToken.class.getName())); } @Override diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java index a0f0221662..341e2cb7b0 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java @@ -18,6 +18,7 @@ package org.springframework.security.web.server.csrf; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @@ -46,9 +47,27 @@ public interface ServerCsrfTokenRequestHandler extends ServerCsrfTokenRequestRes default Mono resolveCsrfTokenValue(ServerWebExchange exchange, CsrfToken csrfToken) { Assert.notNull(exchange, "exchange cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); - return exchange.getFormData() - .flatMap((data) -> Mono.justOrEmpty(data.getFirst(csrfToken.getParameterName()))) - .switchIfEmpty(Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst(csrfToken.getHeaderName()))); + + String headerName = csrfToken.getHeaderName(); + String parameterName = csrfToken.getParameterName(); + + return exchange.getFormData().flatMap((data) -> { + String token = data.getFirst(parameterName); + if (token != null) { + return Mono.just(token); + } + ServerCsrfTokenRequestHandlerLoggerHolder.logger + .trace(LogMessage.format("Did not find a CSRF token in the [%s] request parameter", parameterName)); + return Mono.empty(); + }).switchIfEmpty(Mono.defer(() -> { + String token = exchange.getRequest().getHeaders().getFirst(headerName); + if (token != null) { + return Mono.just(token); + } + ServerCsrfTokenRequestHandlerLoggerHolder.logger + .trace(LogMessage.format("Did not find a CSRF token in the [%s] request header", headerName)); + return Mono.empty(); + })); } } diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java new file mode 100644 index 0000000000..b6cddf1e4d --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.server.csrf; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utility class for holding the logger for {@link ServerCsrfTokenRequestHandler} + */ +final class ServerCsrfTokenRequestHandlerLoggerHolder { + + static final Log logger = LogFactory.getLog(ServerCsrfTokenRequestHandler.class); + + private ServerCsrfTokenRequestHandlerLoggerHolder() { + } + +} diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java index 32e3642351..184a8ee8a8 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,11 @@ package org.springframework.security.web.server.csrf; import java.security.SecureRandom; import java.util.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @@ -32,10 +35,13 @@ import org.springframework.web.server.ServerWebExchange; * masked value as either a form data value or header of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public final class XorServerCsrfTokenRequestAttributeHandler extends ServerCsrfTokenRequestAttributeHandler { + private static final Log logger = LogFactory.getLog(XorServerCsrfTokenRequestAttributeHandler.class); + private SecureRandom secureRandom = new SecureRandom(); /** @@ -72,12 +78,16 @@ public final class XorServerCsrfTokenRequestAttributeHandler extends ServerCsrfT actualBytes = Base64.getUrlDecoder().decode(actualToken); } catch (Exception ex) { + logger.trace(LogMessage.format("Not returning the CSRF token since it's not Base64-encoded"), ex); return null; } byte[] tokenBytes = Utf8.encode(token); int tokenSize = tokenBytes.length; if (actualBytes.length != tokenSize * 2) { + logger.trace(LogMessage.format( + "Not returning the CSRF token since its Base64-decoded length (%d) is not equal to (%d)", + actualBytes.length, tokenSize * 2)); return null; } From d48c463c0329ed1c9fc9190cfe2460885fafe817 Mon Sep 17 00:00:00 2001 From: yybmion Date: Fri, 25 Apr 2025 02:26:48 +0900 Subject: [PATCH 193/504] Add logging to CsrfTokenRequestHandler implementations Add trace-level logging to show the logical path of CSRF token processing - Log token source (header or parameter) in resolveCsrfTokenValue - Log request attribute names in handle methods - Log failures in XorCsrfTokenRequestAttributeHandler (especially Base64 decoding) - Add similar logging to XorServerCsrfTokenRequestAttributeHandler Improves debugging capabilities without changing functionality. Closes gh-13626 Signed-off-by: yybmion --- .../security/web/csrf/CsrfFilter.java | 3 ++ .../CsrfTokenRequestAttributeHandler.java | 11 ++++++- .../web/csrf/CsrfTokenRequestHandler.java | 20 +++++++++--- .../CsrfTokenRequestHandlerLoggerHolder.java | 32 +++++++++++++++++++ .../XorCsrfTokenRequestAttributeHandler.java | 15 ++++++++- ...erverCsrfTokenRequestAttributeHandler.java | 9 +++++- .../csrf/ServerCsrfTokenRequestHandler.java | 25 +++++++++++++-- ...erCsrfTokenRequestHandlerLoggerHolder.java | 32 +++++++++++++++++++ ...erverCsrfTokenRequestAttributeHandler.java | 12 ++++++- 9 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java create mode 100644 web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java index 2164675c74..f2e52554d0 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfFilter.java @@ -119,6 +119,9 @@ public final class CsrfFilter extends OncePerRequestFilter { } CsrfToken csrfToken = deferredCsrfToken.get(); String actualToken = this.requestHandler.resolveCsrfTokenValue(request, csrfToken); + if (actualToken != null && this.logger.isTraceEnabled()) { + this.logger.trace(LogMessage.format("Found a CSRF token in the request")); + } if (!equalsConstantTime(csrfToken.getToken(), actualToken)) { boolean missingToken = deferredCsrfToken.isGenerated(); this.logger diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java index a0950fa44b..7e9a124c4d 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,10 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; /** @@ -29,10 +32,13 @@ import org.springframework.util.Assert; * value as either a header or parameter value of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public class CsrfTokenRequestAttributeHandler implements CsrfTokenRequestHandler { + private static final Log logger = LogFactory.getLog(CsrfTokenRequestAttributeHandler.class); + private String csrfRequestAttributeName = "_csrf"; /** @@ -60,6 +66,9 @@ public class CsrfTokenRequestAttributeHandler implements CsrfTokenRequestHandler String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName : csrfToken.getParameterName(); request.setAttribute(csrfAttrName, csrfToken); + + logger.trace(LogMessage.format("Wrote a CSRF token to the following request attributes: [%s, %s]", csrfAttrName, + CsrfToken.class.getName())); } @SuppressWarnings("serial") diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java index cbdf7d76dc..320c556faf 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; /** @@ -30,6 +31,7 @@ import org.springframework.util.Assert; * available to the application through request attributes. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 * @see CsrfTokenRequestAttributeHandler */ @@ -49,10 +51,20 @@ public interface CsrfTokenRequestHandler extends CsrfTokenRequestResolver { Assert.notNull(request, "request cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); String actualToken = request.getHeader(csrfToken.getHeaderName()); - if (actualToken == null) { - actualToken = request.getParameter(csrfToken.getParameterName()); + if (actualToken != null) { + return actualToken; } - return actualToken; + CsrfTokenRequestHandlerLoggerHolder.logger.trace( + LogMessage.format("Did not find a CSRF token in the [%s] request header", csrfToken.getHeaderName())); + + actualToken = request.getParameter(csrfToken.getParameterName()); + if (actualToken != null) { + return actualToken; + } + CsrfTokenRequestHandlerLoggerHolder.logger.trace(LogMessage + .format("Did not find a CSRF token in the [%s] request parameter", csrfToken.getParameterName())); + + return null; } } diff --git a/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java new file mode 100644 index 0000000000..d90f675b56 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/csrf/CsrfTokenRequestHandlerLoggerHolder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.csrf; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utility class for holding the logger for {@link CsrfTokenRequestHandler} + */ +final class CsrfTokenRequestHandlerLoggerHolder { + + static final Log logger = LogFactory.getLog(CsrfTokenRequestHandler.class); + + private CsrfTokenRequestHandlerLoggerHolder() { + } + +} diff --git a/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java index 9416d233eb..a59920e83f 100644 --- a/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/csrf/XorCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,10 @@ import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.log.LogMessage; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; @@ -32,10 +35,13 @@ import org.springframework.util.Assert; * value from the masked value as either a header or parameter value of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestAttributeHandler { + private static final Log logger = LogFactory.getLog(XorCsrfTokenRequestAttributeHandler.class); + private SecureRandom secureRandom = new SecureRandom(); /** @@ -70,6 +76,9 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA @Override public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { String actualToken = super.resolveCsrfTokenValue(request, csrfToken); + if (actualToken == null) { + return null; + } return getTokenValue(actualToken, csrfToken.getToken()); } @@ -79,12 +88,16 @@ public final class XorCsrfTokenRequestAttributeHandler extends CsrfTokenRequestA actualBytes = Base64.getUrlDecoder().decode(actualToken); } catch (Exception ex) { + logger.trace(LogMessage.format("Not returning the CSRF token since it's not Base64-encoded"), ex); return null; } byte[] tokenBytes = Utf8.encode(token); int tokenSize = tokenBytes.length; if (actualBytes.length != tokenSize * 2) { + logger.trace(LogMessage.format( + "Not returning the CSRF token since its Base64-decoded length (%d) is not equal to (%d)", + actualBytes.length, tokenSize * 2)); return null; } diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java index 888239d522..949c54ab06 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,11 @@ package org.springframework.security.web.server.csrf; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.codec.multipart.FormFieldPart; @@ -31,10 +34,13 @@ import org.springframework.web.server.ServerWebExchange; * resolving the token value as either a form data value or header of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public class ServerCsrfTokenRequestAttributeHandler implements ServerCsrfTokenRequestHandler { + private static final Log logger = LogFactory.getLog(ServerCsrfTokenRequestAttributeHandler.class); + private boolean isTokenFromMultipartDataEnabled; @Override @@ -42,6 +48,7 @@ public class ServerCsrfTokenRequestAttributeHandler implements ServerCsrfTokenRe Assert.notNull(exchange, "exchange cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); exchange.getAttributes().put(CsrfToken.class.getName(), csrfToken); + logger.trace(LogMessage.format("Wrote a CSRF token to the [%s] exchange attribute", CsrfToken.class.getName())); } @Override diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java index a0f0221662..341e2cb7b0 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandler.java @@ -18,6 +18,7 @@ package org.springframework.security.web.server.csrf; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @@ -46,9 +47,27 @@ public interface ServerCsrfTokenRequestHandler extends ServerCsrfTokenRequestRes default Mono resolveCsrfTokenValue(ServerWebExchange exchange, CsrfToken csrfToken) { Assert.notNull(exchange, "exchange cannot be null"); Assert.notNull(csrfToken, "csrfToken cannot be null"); - return exchange.getFormData() - .flatMap((data) -> Mono.justOrEmpty(data.getFirst(csrfToken.getParameterName()))) - .switchIfEmpty(Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst(csrfToken.getHeaderName()))); + + String headerName = csrfToken.getHeaderName(); + String parameterName = csrfToken.getParameterName(); + + return exchange.getFormData().flatMap((data) -> { + String token = data.getFirst(parameterName); + if (token != null) { + return Mono.just(token); + } + ServerCsrfTokenRequestHandlerLoggerHolder.logger + .trace(LogMessage.format("Did not find a CSRF token in the [%s] request parameter", parameterName)); + return Mono.empty(); + }).switchIfEmpty(Mono.defer(() -> { + String token = exchange.getRequest().getHeaders().getFirst(headerName); + if (token != null) { + return Mono.just(token); + } + ServerCsrfTokenRequestHandlerLoggerHolder.logger + .trace(LogMessage.format("Did not find a CSRF token in the [%s] request header", headerName)); + return Mono.empty(); + })); } } diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java new file mode 100644 index 0000000000..b6cddf1e4d --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/server/csrf/ServerCsrfTokenRequestHandlerLoggerHolder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.server.csrf; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utility class for holding the logger for {@link ServerCsrfTokenRequestHandler} + */ +final class ServerCsrfTokenRequestHandlerLoggerHolder { + + static final Log logger = LogFactory.getLog(ServerCsrfTokenRequestHandler.class); + + private ServerCsrfTokenRequestHandlerLoggerHolder() { + } + +} diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java b/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java index 32e3642351..184a8ee8a8 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/XorServerCsrfTokenRequestAttributeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,11 @@ package org.springframework.security.web.server.csrf; import java.security.SecureRandom; import java.util.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; +import org.springframework.core.log.LogMessage; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; @@ -32,10 +35,13 @@ import org.springframework.web.server.ServerWebExchange; * masked value as either a form data value or header of the request. * * @author Steve Riesenberg + * @author Yoobin Yoon * @since 5.8 */ public final class XorServerCsrfTokenRequestAttributeHandler extends ServerCsrfTokenRequestAttributeHandler { + private static final Log logger = LogFactory.getLog(XorServerCsrfTokenRequestAttributeHandler.class); + private SecureRandom secureRandom = new SecureRandom(); /** @@ -72,12 +78,16 @@ public final class XorServerCsrfTokenRequestAttributeHandler extends ServerCsrfT actualBytes = Base64.getUrlDecoder().decode(actualToken); } catch (Exception ex) { + logger.trace(LogMessage.format("Not returning the CSRF token since it's not Base64-encoded"), ex); return null; } byte[] tokenBytes = Utf8.encode(token); int tokenSize = tokenBytes.length; if (actualBytes.length != tokenSize * 2) { + logger.trace(LogMessage.format( + "Not returning the CSRF token since its Base64-decoded length (%d) is not equal to (%d)", + actualBytes.length, tokenSize * 2)); return null; } From ec462e8bc5b7ca9e64b60182eb270182de801b23 Mon Sep 17 00:00:00 2001 From: Danilo Piazzalunga Date: Thu, 8 May 2025 20:37:47 +0000 Subject: [PATCH 194/504] Update assertingparty property usage in YAML snippets Spring Boot 2.7 renamed spring.security.saml2.relyingparty.registration.*.identityprovider.* to spring.security.saml2.relyingparty.registration.*.assertingparty.*. Closes gh-12810. Signed-off-by: Danilo Piazzalunga --- .../pages/servlet/saml2/login/authentication-requests.adoc | 2 +- docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc index 4e0ec21d32..1195cb2933 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc @@ -67,7 +67,7 @@ spring: saml2: relyingparty: okta: - identityprovider: + assertingparty: entity-id: ... singlesignon.sign-request: false ---- diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc index 396edb8bd2..53b0fc3fcb 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc @@ -125,7 +125,7 @@ spring: relyingparty: registration: adfs: - identityprovider: + assertingparty: entity-id: https://idp.example.com/issuer verification.credentials: - certificate-location: "classpath:idp.crt" @@ -839,11 +839,11 @@ spring: signing.credentials: &relying-party-credentials - private-key-location: classpath:rp.key certificate-location: classpath:rp.crt - identityprovider: + assertingparty: entity-id: ... azure: signing.credentials: *relying-party-credentials - identityprovider: + assertingparty: entity-id: ... ---- From 27319e3f9b304194ef601f4e0f95987a0a33daea Mon Sep 17 00:00:00 2001 From: Danilo Piazzalunga Date: Thu, 8 May 2025 20:46:25 +0000 Subject: [PATCH 195/504] Add missing registration property in YAML listing Signed-off-by: Danilo Piazzalunga --- .../saml2/login/authentication-requests.adoc | 9 ++++---- .../pages/servlet/saml2/login/overview.adoc | 21 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc index 1195cb2933..2f794becf3 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc @@ -66,10 +66,11 @@ spring: security: saml2: relyingparty: - okta: - assertingparty: - entity-id: ... - singlesignon.sign-request: false + registration: + okta: + assertingparty: + entity-id: ... + singlesignon.sign-request: false ---- Java:: diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc index 53b0fc3fcb..e394fb2a08 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc @@ -835,16 +835,17 @@ spring: security: saml2: relyingparty: - okta: - signing.credentials: &relying-party-credentials - - private-key-location: classpath:rp.key - certificate-location: classpath:rp.crt - assertingparty: - entity-id: ... - azure: - signing.credentials: *relying-party-credentials - assertingparty: - entity-id: ... + registration: + okta: + signing.credentials: &relying-party-credentials + - private-key-location: classpath:rp.key + certificate-location: classpath:rp.crt + assertingparty: + entity-id: ... + azure: + signing.credentials: *relying-party-credentials + assertingparty: + entity-id: ... ---- Second, in a database, you need not replicate the model of `RelyingPartyRegistration`. From a001f276905b4ac2e26c35a40a917d2cd0ebf3c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:10:12 +0000 Subject: [PATCH 196/504] Bump org-apache-maven-resolver from 1.9.22 to 1.9.23 Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23. Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23 --- updated-dependencies: - dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-impl dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-transport-http dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 954255d36d..cd72d79ca9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ io-spring-javaformat = "0.0.43" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" -org-apache-maven-resolver = "1.9.22" +org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.78.1" org-eclipse-jetty = "11.0.25" From 11eac05dfd52c4a376ba78265e84f8a2a6aeff39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:27:01 +0000 Subject: [PATCH 197/504] Bump org-apache-maven-resolver from 1.9.22 to 1.9.23 Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23. Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23 --- updated-dependencies: - dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-impl dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-transport-http dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9246c0a9d5..70f54948c9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ io-spring-javaformat = "0.0.43" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" -org-apache-maven-resolver = "1.9.22" +org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.79" org-eclipse-jetty = "11.0.25" From 7a62f4eec8a39f825630ebfbb4fe9e389dd8195e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:29:00 +0000 Subject: [PATCH 198/504] Bump org-apache-maven-resolver from 1.9.22 to 1.9.23 Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23. Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23 --- updated-dependencies: - dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-impl dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-transport-http dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0a36397696..69cbb1cd94 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ io-spring-javaformat = "0.0.43" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" -org-apache-maven-resolver = "1.9.22" +org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" From 99330bfc60704252ae3487df380dd4ef441f8bd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:47:41 +0000 Subject: [PATCH 199/504] Bump org-apache-maven-resolver from 1.9.22 to 1.9.23 Bumps `org-apache-maven-resolver` from 1.9.22 to 1.9.23. Updates `org.apache.maven.resolver:maven-resolver-connector-basic` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-impl` from 1.9.22 to 1.9.23 - [Release notes](https://github.com/apache/maven-resolver/releases) - [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.22...maven-resolver-1.9.23) Updates `org.apache.maven.resolver:maven-resolver-transport-http` from 1.9.22 to 1.9.23 --- updated-dependencies: - dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-impl dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.resolver:maven-resolver-transport-http dependency-version: 1.9.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a4ed86714..40d54aebf0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ io-spring-javaformat = "0.0.43" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" -org-apache-maven-resolver = "1.9.22" +org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" From ad934efc245ac1cab21c82f8ce80208653836e30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:27:46 +0000 Subject: [PATCH 200/504] Bump org.hibernate.orm:hibernate-core from 6.6.13.Final to 6.6.14.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.13.Final to 6.6.14.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.14/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.13...6.6.14) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.14.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70f54948c9..bbcdf3b929 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.14.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From c326e394e14e585031dfe33bdf12f0f676c8833b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 03:29:08 +0000 Subject: [PATCH 201/504] Bump org.hibernate.orm:hibernate-core from 6.6.13.Final to 6.6.14.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.13.Final to 6.6.14.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.14/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.13...6.6.14) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.14.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 69cbb1cd94..118ea4ef67 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.13.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.14.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From f1e3f2a8d341594343d5db351d912f6f57f20ea0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 03:21:54 +0000 Subject: [PATCH 202/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.29.1.RELEASE to 0.29.2.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.29.1.RELEASE...0.29.2.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-version: 0.29.2.RELEASE dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40d54aebf0..aa184b3acc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.1.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.2.RELEASE' [plugins] From d34fd236f6efc5338556c9c650e40719503ad482 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 03:36:50 +0000 Subject: [PATCH 203/504] Bump io.micrometer:micrometer-observation from 1.14.6 to 1.14.7 Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.6 to 1.14.7. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.14.7) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-observation dependency-version: 1.14.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bbcdf3b929..422ac60c3a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version. com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" -io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" +io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.7" io-mockk = "io.mockk:mockk:1.13.17" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } From b9a92e35b90954eb1f15a750ed997859745927cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 04:13:18 +0000 Subject: [PATCH 204/504] Bump io.micrometer:micrometer-observation from 1.14.6 to 1.14.7 Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.6 to 1.14.7. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.14.7) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-observation dependency-version: 1.14.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 118ea4ef67..dd14fa788b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" -io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" +io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.7" io-mockk = "io.mockk:mockk:1.14.2" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } From eee7e5edaab86035cd48c967560b81f242c71797 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 04:13:04 +0000 Subject: [PATCH 205/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.29.1.RELEASE to 0.29.2.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.29.1.RELEASE...0.29.2.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-version: 0.29.2.RELEASE dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd14fa788b..9585db92b2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.1.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.2.RELEASE' [plugins] From 2090f44f74ffe099745006526712feb627bf613e Mon Sep 17 00:00:00 2001 From: David Kowis Date: Thu, 8 May 2025 12:35:59 -0500 Subject: [PATCH 206/504] Fix DPoP jkt claim to be JWK SHA-256 thumbprint Just used the nimbus JOSE library to do it, because it already has a compliant implementation. Closes gh-17080 Signed-off-by: David Kowis --- .../DPoPAuthenticationProvider.java | 11 ++++------ .../DPoPAuthenticationProviderTests.java | 20 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index 32d7b09fa1..aa98e6c2f5 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -210,25 +210,22 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return OAuth2TokenValidatorResult.failure(error); } - PublicKey publicKey = null; + JWK jwk = null; @SuppressWarnings("unchecked") Map jwkJson = (Map) jwt.getHeaders().get("jwk"); try { - JWK jwk = JWK.parse(jwkJson); - if (jwk instanceof AsymmetricJWK) { - publicKey = ((AsymmetricJWK) jwk).toPublicKey(); - } + jwk = JWK.parse(jwkJson); } catch (Exception ignored) { } - if (publicKey == null) { + if (jwk == null) { OAuth2Error error = createOAuth2Error("jwk header is missing or invalid."); return OAuth2TokenValidatorResult.failure(error); } String jwkThumbprint; try { - jwkThumbprint = computeSHA256(publicKey); + jwkThumbprint = jwk.computeThumbprint().toString(); } catch (Exception ex) { OAuth2Error error = createOAuth2Error("Failed to compute SHA-256 Thumbprint for jwk."); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java index 08aec38900..bc2d83101e 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; @@ -218,8 +219,8 @@ public class DPoPAuthenticationProviderTests { @Test public void authenticateWhenJktDoesNotMatchThenThrowOAuth2AuthenticationException() throws Exception { - // Use different client public key - Jwt accessToken = generateAccessToken(TestKeys.DEFAULT_EC_KEY_PAIR.getPublic()); + // Use different jwk to make it not match + Jwt accessToken = generateAccessToken(TestJwks.DEFAULT_EC_JWK); JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(accessToken); given(this.tokenAuthenticationManager.authenticate(any())).willReturn(jwtAuthenticationToken); @@ -285,14 +286,14 @@ public class DPoPAuthenticationProviderTests { } private Jwt generateAccessToken() { - return generateAccessToken(TestKeys.DEFAULT_PUBLIC_KEY); + return generateAccessToken(TestJwks.DEFAULT_RSA_JWK); } - private Jwt generateAccessToken(PublicKey clientPublicKey) { + private Jwt generateAccessToken(JWK clientJwk) { Map jktClaim = null; - if (clientPublicKey != null) { + if (clientJwk != null) { try { - String sha256Thumbprint = computeSHA256(clientPublicKey); + String sha256Thumbprint = clientJwk.computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -321,11 +322,4 @@ public class DPoPAuthenticationProviderTests { byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } - - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - } From a265ac6ae7a7aa137521cbc29c1d436439ed4340 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Tue, 13 May 2025 08:15:00 -0400 Subject: [PATCH 207/504] Polish gh-17080 --- .../DPoPAuthenticationConfigurerTests.java | 32 +++++++------------ .../DPoPAuthenticationProvider.java | 8 ----- .../DPoPAuthenticationProviderTests.java | 5 ++- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index d908607a1f..6ffab052e9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; @@ -33,6 +32,7 @@ import java.util.Set; import java.util.UUID; import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.JWKSource; @@ -89,6 +89,8 @@ public class DPoPAuthenticationConfigurerTests { private static final ECPrivateKey CLIENT_EC_PRIVATE_KEY = (ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate(); + private static final ECKey CLIENT_EC_KEY = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); + private static NimbusJwtEncoder providerJwtEncoder; private static NimbusJwtEncoder clientJwtEncoder; @@ -104,9 +106,8 @@ public class DPoPAuthenticationConfigurerTests { JWKSource providerJwkSource = (jwkSelector, securityContext) -> jwkSelector .select(new JWKSet(providerRsaKey)); providerJwtEncoder = new NimbusJwtEncoder(providerJwkSource); - ECKey clientEcKey = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); JWKSource clientJwkSource = (jwkSelector, securityContext) -> jwkSelector - .select(new JWKSet(clientEcKey)); + .select(new JWKSet(CLIENT_EC_KEY)); clientJwtEncoder = new NimbusJwtEncoder(clientJwkSource); } @@ -114,7 +115,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAndBearerAuthenticationThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -131,7 +132,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAccessTokenMalformedThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -147,7 +148,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenMultipleDPoPProofsThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -164,7 +165,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAuthenticationValidThenAccessed() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -175,11 +176,11 @@ public class DPoPAuthenticationConfigurerTests { // @formatter:on } - private static String generateAccessToken(Set scope, PublicKey clientPublicKey) { + private static String generateAccessToken(Set scope, JWK jwk) { Map jktClaim = null; - if (clientPublicKey != null) { + if (jwk != null) { try { - String sha256Thumbprint = computeSHA256(clientPublicKey); + String sha256Thumbprint = jwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -207,10 +208,7 @@ public class DPoPAuthenticationConfigurerTests { private static String generateDPoPProof(String method, String resourceUri, String accessToken) throws Exception { // @formatter:off - Map publicJwk = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY) - .build() - .toPublicJWK() - .toJSONObject(); + Map publicJwk = CLIENT_EC_KEY.toPublicJWK().toJSONObject(); JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.ES256) .type("dpop+jwt") .jwk(publicJwk) @@ -233,12 +231,6 @@ public class DPoPAuthenticationConfigurerTests { return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - @Configuration @EnableWebSecurity @EnableWebMvc diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index aa98e6c2f5..0b904254f8 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -18,13 +18,11 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.util.Base64; import java.util.Map; import java.util.function.Function; -import com.nimbusds.jose.jwk.AsymmetricJWK; import com.nimbusds.jose.jwk.JWK; import org.springframework.security.authentication.AuthenticationManager; @@ -243,12 +241,6 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF, reason, null); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - } private static final class OAuth2AccessTokenClaims implements OAuth2Token, ClaimAccessor { diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java index bc2d83101e..faa84d8cb4 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java @@ -18,7 +18,6 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Base64; @@ -37,7 +36,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.jose.TestJwks; -import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; @@ -293,7 +291,7 @@ public class DPoPAuthenticationProviderTests { Map jktClaim = null; if (clientJwk != null) { try { - String sha256Thumbprint = clientJwk.computeThumbprint().toString(); + String sha256Thumbprint = clientJwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -322,4 +320,5 @@ public class DPoPAuthenticationProviderTests { byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } + } From 8b925dc4fca6a483e8273c863aa24fe260f91786 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 03:22:06 +0000 Subject: [PATCH 208/504] Bump io.micrometer:micrometer-observation from 1.14.6 to 1.14.7 Bumps [io.micrometer:micrometer-observation](https://github.com/micrometer-metrics/micrometer) from 1.14.6 to 1.14.7. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.14.7) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-observation dependency-version: 1.14.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa184b3acc..dd5a8ae205 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" -io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.6" +io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.7" io-mockk = "io.mockk:mockk:1.14.2" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M2" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } From 462e38c0e36c57f073e68ba4bbfae1ff0fa5606e Mon Sep 17 00:00:00 2001 From: David Kowis Date: Thu, 8 May 2025 12:35:59 -0500 Subject: [PATCH 209/504] Fix DPoP jkt claim to be JWK SHA-256 thumbprint Just used the nimbus JOSE library to do it, because it already has a compliant implementation. Closes gh-17080 Signed-off-by: David Kowis --- .../DPoPAuthenticationProvider.java | 11 ++++------ .../DPoPAuthenticationProviderTests.java | 20 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index 32d7b09fa1..aa98e6c2f5 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -210,25 +210,22 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return OAuth2TokenValidatorResult.failure(error); } - PublicKey publicKey = null; + JWK jwk = null; @SuppressWarnings("unchecked") Map jwkJson = (Map) jwt.getHeaders().get("jwk"); try { - JWK jwk = JWK.parse(jwkJson); - if (jwk instanceof AsymmetricJWK) { - publicKey = ((AsymmetricJWK) jwk).toPublicKey(); - } + jwk = JWK.parse(jwkJson); } catch (Exception ignored) { } - if (publicKey == null) { + if (jwk == null) { OAuth2Error error = createOAuth2Error("jwk header is missing or invalid."); return OAuth2TokenValidatorResult.failure(error); } String jwkThumbprint; try { - jwkThumbprint = computeSHA256(publicKey); + jwkThumbprint = jwk.computeThumbprint().toString(); } catch (Exception ex) { OAuth2Error error = createOAuth2Error("Failed to compute SHA-256 Thumbprint for jwk."); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java index 08aec38900..bc2d83101e 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; @@ -218,8 +219,8 @@ public class DPoPAuthenticationProviderTests { @Test public void authenticateWhenJktDoesNotMatchThenThrowOAuth2AuthenticationException() throws Exception { - // Use different client public key - Jwt accessToken = generateAccessToken(TestKeys.DEFAULT_EC_KEY_PAIR.getPublic()); + // Use different jwk to make it not match + Jwt accessToken = generateAccessToken(TestJwks.DEFAULT_EC_JWK); JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(accessToken); given(this.tokenAuthenticationManager.authenticate(any())).willReturn(jwtAuthenticationToken); @@ -285,14 +286,14 @@ public class DPoPAuthenticationProviderTests { } private Jwt generateAccessToken() { - return generateAccessToken(TestKeys.DEFAULT_PUBLIC_KEY); + return generateAccessToken(TestJwks.DEFAULT_RSA_JWK); } - private Jwt generateAccessToken(PublicKey clientPublicKey) { + private Jwt generateAccessToken(JWK clientJwk) { Map jktClaim = null; - if (clientPublicKey != null) { + if (clientJwk != null) { try { - String sha256Thumbprint = computeSHA256(clientPublicKey); + String sha256Thumbprint = clientJwk.computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -321,11 +322,4 @@ public class DPoPAuthenticationProviderTests { byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } - - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - } From 44303d2c80d01eef30ea4219296ed4cd09ec52e7 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Tue, 13 May 2025 08:15:00 -0400 Subject: [PATCH 210/504] Polish gh-17080 --- .../DPoPAuthenticationConfigurerTests.java | 32 +++++++------------ .../DPoPAuthenticationProvider.java | 8 ----- .../DPoPAuthenticationProviderTests.java | 5 ++- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index d908607a1f..6ffab052e9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; @@ -33,6 +32,7 @@ import java.util.Set; import java.util.UUID; import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.JWKSource; @@ -89,6 +89,8 @@ public class DPoPAuthenticationConfigurerTests { private static final ECPrivateKey CLIENT_EC_PRIVATE_KEY = (ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate(); + private static final ECKey CLIENT_EC_KEY = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); + private static NimbusJwtEncoder providerJwtEncoder; private static NimbusJwtEncoder clientJwtEncoder; @@ -104,9 +106,8 @@ public class DPoPAuthenticationConfigurerTests { JWKSource providerJwkSource = (jwkSelector, securityContext) -> jwkSelector .select(new JWKSet(providerRsaKey)); providerJwtEncoder = new NimbusJwtEncoder(providerJwkSource); - ECKey clientEcKey = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); JWKSource clientJwkSource = (jwkSelector, securityContext) -> jwkSelector - .select(new JWKSet(clientEcKey)); + .select(new JWKSet(CLIENT_EC_KEY)); clientJwtEncoder = new NimbusJwtEncoder(clientJwkSource); } @@ -114,7 +115,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAndBearerAuthenticationThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -131,7 +132,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAccessTokenMalformedThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -147,7 +148,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenMultipleDPoPProofsThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -164,7 +165,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAuthenticationValidThenAccessed() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -175,11 +176,11 @@ public class DPoPAuthenticationConfigurerTests { // @formatter:on } - private static String generateAccessToken(Set scope, PublicKey clientPublicKey) { + private static String generateAccessToken(Set scope, JWK jwk) { Map jktClaim = null; - if (clientPublicKey != null) { + if (jwk != null) { try { - String sha256Thumbprint = computeSHA256(clientPublicKey); + String sha256Thumbprint = jwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -207,10 +208,7 @@ public class DPoPAuthenticationConfigurerTests { private static String generateDPoPProof(String method, String resourceUri, String accessToken) throws Exception { // @formatter:off - Map publicJwk = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY) - .build() - .toPublicJWK() - .toJSONObject(); + Map publicJwk = CLIENT_EC_KEY.toPublicJWK().toJSONObject(); JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.ES256) .type("dpop+jwt") .jwk(publicJwk) @@ -233,12 +231,6 @@ public class DPoPAuthenticationConfigurerTests { return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - @Configuration @EnableWebSecurity @EnableWebMvc diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index aa98e6c2f5..0b904254f8 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -18,13 +18,11 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.util.Base64; import java.util.Map; import java.util.function.Function; -import com.nimbusds.jose.jwk.AsymmetricJWK; import com.nimbusds.jose.jwk.JWK; import org.springframework.security.authentication.AuthenticationManager; @@ -243,12 +241,6 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF, reason, null); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - } private static final class OAuth2AccessTokenClaims implements OAuth2Token, ClaimAccessor { diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java index bc2d83101e..faa84d8cb4 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java @@ -18,7 +18,6 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Base64; @@ -37,7 +36,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.jose.TestJwks; -import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; @@ -293,7 +291,7 @@ public class DPoPAuthenticationProviderTests { Map jktClaim = null; if (clientJwk != null) { try { - String sha256Thumbprint = clientJwk.computeThumbprint().toString(); + String sha256Thumbprint = clientJwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -322,4 +320,5 @@ public class DPoPAuthenticationProviderTests { byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } + } From 86550fb84b19590ef4cfb656efd44a18662c01db Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sat, 10 May 2025 02:17:47 +0700 Subject: [PATCH 211/504] Cleanup code Signed-off-by: Tran Ngoc Nhan --- .../WebSessionServerRequestCache.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/server/savedrequest/WebSessionServerRequestCache.java b/web/src/main/java/org/springframework/security/web/server/savedrequest/WebSessionServerRequestCache.java index 2c1f8aac10..396d93fb25 100644 --- a/web/src/main/java/org/springframework/security/web/server/savedrequest/WebSessionServerRequestCache.java +++ b/web/src/main/java/org/springframework/security/web/server/savedrequest/WebSessionServerRequestCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,7 +64,8 @@ public class WebSessionServerRequestCache implements ServerRequestCache { /** * Sets the matcher to determine if the request should be saved. The default is to * match on any GET request. - * @param saveRequestMatcher + * @param saveRequestMatcher the {@link ServerWebExchangeMatcher} that determines if + * the request should be saved */ public void setSaveRequestMatcher(ServerWebExchangeMatcher saveRequestMatcher) { Assert.notNull(saveRequestMatcher, "saveRequestMatcher cannot be null"); @@ -96,7 +97,7 @@ public class WebSessionServerRequestCache implements ServerRequestCache { public Mono removeMatchingRequest(ServerWebExchange exchange) { MultiValueMap queryParams = exchange.getRequest().getQueryParams(); if (this.matchingRequestParameterName != null && !queryParams.containsKey(this.matchingRequestParameterName)) { - this.logger.trace( + logger.trace( "matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided"); return Mono.empty(); } @@ -165,17 +166,4 @@ public class WebSessionServerRequestCache implements ServerRequestCache { return new AndServerWebExchangeMatcher(get, notFavicon, html); } - private static String createQueryString(String queryString, String matchingRequestParameterName) { - if (matchingRequestParameterName == null) { - return queryString; - } - if (queryString == null || queryString.length() == 0) { - return matchingRequestParameterName; - } - if (queryString.endsWith("&")) { - return queryString + matchingRequestParameterName; - } - return queryString + "&" + matchingRequestParameterName; - } - } From a5111713095e4d13a4a7dda4441ebc71120aa751 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Thu, 8 May 2025 18:02:43 +0700 Subject: [PATCH 212/504] Add test and update javadoc for CommonOAuth2Provider Signed-off-by: Tran Ngoc Nhan --- .../oauth2/client/CommonOAuth2Provider.java | 5 +++-- .../client/CommonOAuth2ProviderTests.java | 20 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java index 96d0e51eac..c2e84336f6 100644 --- a/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java +++ b/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.security.config.oauth2.client; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; @@ -27,7 +28,7 @@ import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; * Common OAuth2 Providers that can be used to create * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder * builders} pre-configured with sensible defaults for the - * {@link HttpSecurity#oauth2Login()} flow. + * {@link HttpSecurity#oauth2Login(Customizer)} flow. * * @author Phillip Webb * @since 5.0 diff --git a/config/src/test/java/org/springframework/security/config/oauth2/client/CommonOAuth2ProviderTests.java b/config/src/test/java/org/springframework/security/config/oauth2/client/CommonOAuth2ProviderTests.java index 81ab751a60..0a3bea1389 100644 --- a/config/src/test/java/org/springframework/security/config/oauth2/client/CommonOAuth2ProviderTests.java +++ b/config/src/test/java/org/springframework/security/config/oauth2/client/CommonOAuth2ProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -115,6 +115,24 @@ public class CommonOAuth2ProviderTests { assertThat(registration.getRegistrationId()).isEqualTo("123"); } + @Test + public void getBuilderWhenXShouldHaveXSettings() { + ClientRegistration registration = build(CommonOAuth2Provider.X); + ProviderDetails providerDetails = registration.getProviderDetails(); + assertThat(providerDetails.getAuthorizationUri()).isEqualTo("https://x.com/i/oauth2/authorize"); + assertThat(providerDetails.getTokenUri()).isEqualTo("https://api.x.com/2/oauth2/token"); + assertThat(providerDetails.getUserInfoEndpoint().getUri()).isEqualTo("https://api.x.com/2/users/me"); + assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName()).isEqualTo("username"); + assertThat(providerDetails.getJwkSetUri()).isNull(); + assertThat(registration.getClientAuthenticationMethod()) + .isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_POST); + assertThat(registration.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); + assertThat(registration.getRedirectUri()).isEqualTo(DEFAULT_REDIRECT_URL); + assertThat(registration.getScopes()).containsOnly("users.read", "tweet.read"); + assertThat(registration.getClientName()).isEqualTo("X"); + assertThat(registration.getRegistrationId()).isEqualTo("123"); + } + private ClientRegistration build(CommonOAuth2Provider provider) { return builder(provider).build(); } From 78a60d0d84c04e20cca61601b21bdb350f4b93ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 03:23:25 +0000 Subject: [PATCH 213/504] Bump io.projectreactor:reactor-bom from 2023.0.17 to 2023.0.18 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.17 to 2023.0.18. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.17...2023.0.18) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.18 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cd72d79ca9..39589d0b65 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.12.13" io-mockk = "io.mockk:mockk:1.13.17" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.17" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.18" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 91afd49faf7d35a82ae8a3758bc50f5756813717 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 03:33:33 +0000 Subject: [PATCH 214/504] Bump org.hibernate.orm:hibernate-core from 6.6.14.Final to 6.6.15.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.14.Final to 6.6.15.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.15/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.14...6.6.15) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.15.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 422ac60c3a..1f89779ddc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.14.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.15.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 5f7155bfc75a488fdd91e983ac4e947d80f74950 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Wed, 14 May 2025 05:21:00 -0400 Subject: [PATCH 215/504] Implement internal cache in JtiClaimValidator Closes gh-17107 --- .../jwt/DPoPProofJwtDecoderFactory.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java index 509d0d25eb..6970b449c6 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/DPoPProofJwtDecoderFactory.java @@ -18,12 +18,12 @@ package org.springframework.security.oauth2.jwt; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.time.Clock; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Base64; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import com.nimbusds.jose.JOSEException; @@ -146,7 +146,7 @@ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory { - private static final Map jtiCache = new ConcurrentHashMap<>(); + private static final Map JTI_CACHE = Collections.synchronizedMap(new JtiCache()); @Override public OAuth2TokenValidatorResult validate(Jwt jwt) { @@ -166,8 +166,8 @@ public final class DPoPProofJwtDecoderFactory implements JwtDecoderFactory { + + private static final int MAX_SIZE = 1000; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + if (size() > MAX_SIZE) { + return true; + } + Instant expiry = Instant.ofEpochMilli(eldest.getValue()); + return Instant.now().isAfter(expiry); + } + + } + } } From c22091d8be857793fb6e59e66f5bce17a40d140d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 May 2025 03:50:59 +0000 Subject: [PATCH 216/504] Bump io.projectreactor:reactor-bom from 2025.0.0-M2 to 2025.0.0-M3 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2025.0.0-M2 to 2025.0.0-M3. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2025.0.0-M2...2025.0.0-M3) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2025.0.0-M3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd5a8ae205..47cd26e7c3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.7" io-mockk = "io.mockk:mockk:1.14.2" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M2" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M3" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 3b492a96288d91c71798eb4f536fcc0d625787c4 Mon Sep 17 00:00:00 2001 From: Andrey Litvitski Date: Mon, 12 May 2025 22:43:34 +0300 Subject: [PATCH 217/504] remove 32-byte minimum keyLength restriction in `Base64StringKeyGenerator` (#17012) Signed-off-by: Andrey Litvitski --- .../security/crypto/keygen/Base64StringKeyGenerator.java | 7 ++++--- .../crypto/keygen/Base64StringKeyGeneratorTests.java | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java b/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java index 9b28d68a72..40e89d10fb 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java +++ b/crypto/src/main/java/org/springframework/security/crypto/keygen/Base64StringKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.util.Base64; * * @author Joe Grandja * @author Rob Winch + * @author Andrey Litvitski * @since 5.0 */ public class Base64StringKeyGenerator implements StringKeyGenerator { @@ -67,8 +68,8 @@ public class Base64StringKeyGenerator implements StringKeyGenerator { if (encoder == null) { throw new IllegalArgumentException("encode cannot be null"); } - if (keyLength < DEFAULT_KEY_LENGTH) { - throw new IllegalArgumentException("keyLength must be greater than or equal to " + DEFAULT_KEY_LENGTH); + if (keyLength <= 0) { + throw new IllegalArgumentException("keyLength must be greater than 0"); } this.encoder = encoder; this.keyGenerator = KeyGenerators.secureRandom(keyLength); diff --git a/crypto/src/test/java/org/springframework/security/crypto/keygen/Base64StringKeyGeneratorTests.java b/crypto/src/test/java/org/springframework/security/crypto/keygen/Base64StringKeyGeneratorTests.java index 4590b67683..a781513f68 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/keygen/Base64StringKeyGeneratorTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/keygen/Base64StringKeyGeneratorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,13 +25,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException /** * @author Rob Winch + * @author Andrey Litvitski * @since 5.0 */ public class Base64StringKeyGeneratorTests { @Test - public void constructorIntWhenLessThan32ThenIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> new Base64StringKeyGenerator(31)); + public void constructorIntWhenEqual0ThenIllegalArgumentException() { + assertThatIllegalArgumentException().isThrownBy(() -> new Base64StringKeyGenerator(0)); } @Test From 817938fa49f567bc6f38b63087378b392ef95fc6 Mon Sep 17 00:00:00 2001 From: huhdy32 Date: Sat, 10 May 2025 22:51:12 +0900 Subject: [PATCH 218/504] Add NullReturningMethodAuthorizationDeniedHandler This implementation of MethodAuthorizationDeniedHandler returns null when authorization is denied. Closes gh-16705 Signed-off-by: huhdy32 --- ...rningMethodAuthorizationDeniedHandler.java | 49 ++++++++++++++++ ...MethodAuthorizationDeniedHandlerTests.java | 58 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 core/src/main/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandler.java create mode 100644 core/src/test/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandlerTests.java diff --git a/core/src/main/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandler.java b/core/src/main/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandler.java new file mode 100644 index 0000000000..f81a7cb50b --- /dev/null +++ b/core/src/main/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.authorization.method; + +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.security.authorization.AuthorizationResult; + +/** + * An implementation of {@link MethodAuthorizationDeniedHandler} that return {@code null}. + * + * @author Heejong Yoon + * @since 6.5.0 + */ +public final class NullReturningMethodAuthorizationDeniedHandler implements MethodAuthorizationDeniedHandler { + + @Override + public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) { + if (authorizationResult instanceof AuthorizationDeniedException exception) { + throw exception; + } + return null; + } + + @Override + public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult, + AuthorizationResult authorizationResult) { + if (authorizationResult instanceof AuthorizationDeniedException exception) { + throw exception; + } + return null; + } + +} diff --git a/core/src/test/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandlerTests.java b/core/src/test/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandlerTests.java new file mode 100644 index 0000000000..0064280d1b --- /dev/null +++ b/core/src/test/java/org/springframework/security/authorization/method/NullReturningMethodAuthorizationDeniedHandlerTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.authorization.method; + +import org.junit.jupiter.api.Test; + +import org.springframework.security.authorization.AuthorizationDeniedException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Tests for {@link NullReturningMethodAuthorizationDeniedHandler}. + * + * @author Heejong Yoon + */ +class NullReturningMethodAuthorizationDeniedHandlerTests { + + @Test + void handleNullReturningMethod() { + assertThat(new NullReturningMethodAuthorizationDeniedHandler().handleDeniedInvocation(null, null)).isNull(); + } + + @Test + void handleNullReturningMethodWithException() { + assertThatExceptionOfType(AuthorizationDeniedException.class) + .isThrownBy(() -> new NullReturningMethodAuthorizationDeniedHandler().handleDeniedInvocation(null, + new AuthorizationDeniedException("test"))); + } + + @Test + void handleNullReturningMethodWithInvocationResult() { + assertThat(new NullReturningMethodAuthorizationDeniedHandler().handleDeniedInvocationResult(null, null)) + .isNull(); + } + + @Test + void handleNullReturningMethodWithInvocationResultWithException() { + assertThatExceptionOfType(AuthorizationDeniedException.class) + .isThrownBy(() -> new NullReturningMethodAuthorizationDeniedHandler().handleDeniedInvocationResult(null, + new AuthorizationDeniedException("test"))); + } + +} From 0722c2dc41f3a14db51d3be6629c6278aad703a0 Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Thu, 8 May 2025 01:41:22 +0900 Subject: [PATCH 219/504] Implement UserDetailsPasswordService in JdbcUserDetailsManager Signed-off-by: Junhyeok Lee --- .../provisioning/JdbcUserDetailsManager.java | 30 ++++++++++++++++++- .../JdbcUserDetailsManagerTests.java | 17 +++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index 5856580cce..951e3d25ab 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -46,6 +46,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsPasswordService; import org.springframework.security.core.userdetails.cache.NullUserCache; import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; import org.springframework.util.Assert; @@ -65,7 +66,8 @@ import org.springframework.util.Assert; * @author Luke Taylor * @since 2.0 */ -public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsManager, GroupManager { +public class JdbcUserDetailsManager extends JdbcDaoImpl + implements UserDetailsManager, GroupManager, UserDetailsPasswordService { public static final String DEF_CREATE_USER_SQL = "insert into users (username, password, enabled) values (?,?,?)"; @@ -162,6 +164,8 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa private RowMapper grantedAuthorityMapper = this::mapToGrantedAuthority; + private boolean enableUpdatePassword = false; + public JdbcUserDetailsManager() { } @@ -591,6 +595,20 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa this.userCache = userCache; } + /** + * Sets whether the {@link #updatePassword(UserDetails, String)} method should + * actually update the password. + *

+ * Defaults to {@code false} to prevent accidental password updates that might produce + * passwords that are too large for the current database schema. Users must explicitly + * set this to {@code true} to enable password updates. + * @param enableUpdatePassword {@code true} to enable password updates, {@code false} + * otherwise. + */ + public void setEnableUpdatePassword(boolean enableUpdatePassword) { + this.enableUpdatePassword = enableUpdatePassword; + } + private void validateUserDetails(UserDetails user) { Assert.hasText(user.getUsername(), "Username may not be empty or null"); validateAuthorities(user.getAuthorities()); @@ -604,4 +622,14 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa } } + @Override + public UserDetails updatePassword(UserDetails user, String newPassword) { + if (this.enableUpdatePassword) { + UserDetails updated = User.withUserDetails(user).password(newPassword).build(); + updateUser(updated); + return updated; + } + return user; + } + } diff --git a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java index 5c8ed72b18..db49411c25 100644 --- a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java @@ -410,6 +410,23 @@ public class JdbcUserDetailsManagerTests { verify(mockMapper).mapRow(any(), anyInt()); } + @Test + void updatePasswordWhenDisabledReturnOriginalUser() { + insertJoe(); + this.manager.updatePassword(joe, "new"); + UserDetails newJoe = this.manager.loadUserByUsername("joe"); + assertThat(newJoe.getPassword()).isEqualTo("password"); + } + + @Test + void updatePasswordWhenEnabledShouldUpdatePassword() { + insertJoe(); + this.manager.setEnableUpdatePassword(true); + this.manager.updatePassword(joe, "new"); + UserDetails newJoe = this.manager.loadUserByUsername("joe"); + assertThat(newJoe.getPassword()).isEqualTo("new"); + } + private Authentication authenticateJoe() { UsernamePasswordAuthenticationToken auth = UsernamePasswordAuthenticationToken.authenticated("joe", "password", joe.getAuthorities()); From e30dc42d1e4a969552a205b3bbbeae5f5a78390a Mon Sep 17 00:00:00 2001 From: Junhyeok Lee Date: Sat, 10 May 2025 00:14:44 +0900 Subject: [PATCH 220/504] Update JdbcUserDetailsManager Javadoc and author Signed-off-by: Junhyeok Lee --- .../security/provisioning/JdbcUserDetailsManager.java | 5 +++++ .../security/provisioning/JdbcUserDetailsManagerTests.java | 1 + 2 files changed, 6 insertions(+) diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index 951e3d25ab..5bd8aecdf3 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -64,6 +64,7 @@ import org.springframework.util.Assert; * using this implementation for managing your users. * * @author Luke Taylor + * @author Junhyeok Lee * @since 2.0 */ public class JdbcUserDetailsManager extends JdbcDaoImpl @@ -622,6 +623,10 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl } } + /** + * Conditionally updates password based on the setting from + * {@link #setEnableUpdatePassword(boolean)}. {@inheritDoc} + */ @Override public UserDetails updatePassword(UserDetails user, String newPassword) { if (this.enableUpdatePassword) { diff --git a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java index db49411c25..3f7962e6f4 100644 --- a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java @@ -60,6 +60,7 @@ import static org.mockito.BDDMockito.verify; * * @author Luke Taylor * @author dae won + * @author Junhyeok Lee */ public class JdbcUserDetailsManagerTests { From 4fb3dca9530ee4f6a85b33ff1711753dbcf72c97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 03:27:53 +0000 Subject: [PATCH 221/504] Bump org.hibernate.orm:hibernate-core from 7.0.0.CR1 to 7.0.0.CR2 Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.0.CR1 to 7.0.0.CR2. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.0.CR1...7.0.0.CR2) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.0.CR2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 47cd26e7c3..d99094e4e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.CR1" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.CR2" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 260d298cc5e6173b612744c6295c6e1fb4f024b6 Mon Sep 17 00:00:00 2001 From: snowykte0426 Date: Thu, 1 May 2025 20:06:30 +0900 Subject: [PATCH 222/504] Add Migration Guide from Spring Security SAML Extension This adds a dedicated migration guide for users moving from the Spring Security SAML Extension to the built-in SAML 2.0 support. Includes: - Content migrated from the project wiki - xref links for `saml2Login`, `saml2Logout`, and `saml2Metadata` - Metadata example moved to Examples Matrix - Cleanup and naming per review feedback Closes gh-11161 Signed-off-by: snowykte0426 --- docs/modules/ROOT/nav.adoc | 1 + .../saml2/saml-extension-migration.adoc | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 37052965b8..4f4b8fde95 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -82,6 +82,7 @@ **** xref:servlet/saml2/login/authentication.adoc[SAML2 Authentication Responses] *** xref:servlet/saml2/logout.adoc[SAML2 Logout] *** xref:servlet/saml2/metadata.adoc[SAML2 Metadata] +*** xref:servlet/saml2/saml-extension-migration.adoc[Migrating from Spring Security SAML Extension] ** xref:servlet/exploits/index.adoc[Protection Against Exploits] *** xref:servlet/exploits/csrf.adoc[] *** xref:servlet/exploits/headers.adoc[] diff --git a/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc b/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc new file mode 100644 index 0000000000..c43485ea28 --- /dev/null +++ b/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc @@ -0,0 +1,65 @@ +This document contains guidance for moving SAML 2.0 Service Providers from Spring Security SAML Extensions 1.x to Spring Security Since Spring Security doesn’t provide Identity Provider support, migrating a Spring Security SAML Extensions Identity Provider is out of scope for this document. + +Because the two approaches are as different as they are, this document will tend to cover patterns more than precise search-and-replace steps. + +[[saml2-login-logout]] +== Login & Logout + +=== Changes In Approach + +https://github.com/spring-projects/spring-security[Spring Security] takes a slightly different approach from https://github.com/spring-projects/spring-security-saml[Spring Security SAML Extensions] in a few notable ways. + +==== Simplified Enablement + +Spring Security SAML Extensions support for Service Providers is provided by a series of filters enabled by adding each filter manually in the correct order to various Spring Security filter chains. + +Spring Security’s SAML 2.0 Service Provider support is enabled via the Spring Security DSL methods: +xref:servlet/saml2/login/index.adoc[`saml2Login`], +xref:servlet/saml2/logout.adoc[`saml2Logout`], and +xref:servlet/saml2/metadata.adoc[`saml2Metadata`]. It selects the correct filters to add and puts them in the appropriate places in the filter chain. + +==== Stronger Encapsulation + +Like Spring Security SAML Extensions, Spring Security bases it’s SAML support on OpenSAML. The Extensions project exposes OpenSAML over public interfaces, blurring the lines between the two projects, effectively requiring OpenSAML, and making upgrades to later versions of OpenSAML more complicated. + +Spring Security provides stronger encapsulation. No public interfaces expose OpenSAML components and any class that exposes OpenSAML in its public API is named with an `OpenSaml` prefix for additional clarity. + +==== Out-of-the-box Multitenancy + +Spring Security SAML Extensions offered some lightweight support for declaring more than one Identity Provider and accessing it at login time using the `idp` request parameter. This was limiting as far as changing things at runtime was concerned and also doesn’t allow for a many-to-many relationship between relying and asserting parties. + +Spring Security builds SAML 2.0 multitenancy into its default URLs and basic components in the form of a `RelyingPartyRegistration`. This component acts as a link between a Relying Party’s metadata and an Asserting Party’s metadata, and all pairs are available for lookup in a `RelyingPartyRegistrationRepository`. Each URL represents a unique registration pair to be retrieved. + +Whether it’s AuthnRequests, Responses, LogoutRequests, LogoutResponses, or EntityDescriptors, each filter is based off of `RelyingPartyRegistrationRepository` and so is fundamentally multi-tenant. + +=== Examples Matrix + +Both Spring Security and Spring Security SAML Extensions have examples for how to configure the Service Provider: + +[options="header"] +|=== +| Use case | Spring Security | Spring Security SAML Extension + +| Login & Logout | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/login[Sample] | +https://github.com/jzheaux/spring-security-saml-migrate/tree/main/login-logout[Sample] +| Login using SAML Extension URLs | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/custom-urls[Sample] | - +| Metadata support | https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/saml2/refreshable-metadata[Sample] | - +|=== + +You can also see a showcase example in https://github.com/spring-projects/spring-security-saml/tree/main/sample[Spring Security SAML Extension]'s GitHub project. + + +[NOTE] +==== +Spring Security does not support HTTP-Redirect binding for SAML 2.0 Responses. +According to the SAML specification, the HTTP-Redirect binding is not permitted for SAML Responses due to URL length and signature limitations. Attempting to use this binding may result in unexpected errors. +Use HTTP-POST binding instead when configuring your identity provider. +==== + +[[saml2-unported]] +== Unported Features + +There are some features that are not yet ported over and there are as yet no plans to do so: + +* HTTP-Redirect binding for SAML 2.0 Responses +* Artifact binding support From eb30fd7f591b67bae4bab05358180001072fdab3 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 15 May 2025 18:16:36 -0600 Subject: [PATCH 223/504] Add Missing Header Issue gh-11161 --- .../ROOT/pages/servlet/saml2/saml-extension-migration.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc b/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc index c43485ea28..bcb8c19970 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/saml-extension-migration.adoc @@ -1,3 +1,5 @@ += SAML 2.0 Extension Migration + This document contains guidance for moving SAML 2.0 Service Providers from Spring Security SAML Extensions 1.x to Spring Security Since Spring Security doesn’t provide Identity Provider support, migrating a Spring Security SAML Extensions Identity Provider is out of scope for this document. Because the two approaches are as different as they are, this document will tend to cover patterns more than precise search-and-replace steps. From e5d62e0bdd3a9b93d959f9dcaad0f1a763c9e2e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 03:15:15 +0000 Subject: [PATCH 224/504] Bump org.springframework:spring-framework-bom from 6.2.6 to 6.2.7 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.6 to 6.2.7. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.6...v6.2.7) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e81cc44e39..6dc6a136a7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.6" +org-springframework = "6.2.7" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 0cbc38cdd60fba632b3b5c2e1b12784adb552adb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 03:22:19 +0000 Subject: [PATCH 225/504] Bump org.springframework:spring-framework-bom from 6.1.19 to 6.1.20 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.19 to 6.1.20. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.19...v6.1.20) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 39589d0b65..90982adc54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.19" +org-springframework = "6.1.20" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From a17b2a18d9b642a81da221652ef944f5bf4a300f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 03:30:36 +0000 Subject: [PATCH 226/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.11 to 2024.0.12. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.11...2024.0.12) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90982adc54..02e6579a33 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.11" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 1864c876d1c93fcacea593da4e79db121c1eff9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 03:51:09 +0000 Subject: [PATCH 227/504] Bump org.springframework.data:spring-data-bom from 2024.1.5 to 2024.1.6 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.5 to 2024.1.6. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.5...2024.1.6) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6dc6a136a7..273a381b3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.5" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From cceedd0bffaf8d98c0794c01a1a5f22759b2ec71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 03:57:18 +0000 Subject: [PATCH 228/504] Bump org.springframework.data:spring-data-bom from 2024.1.5 to 2024.1.6 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.5 to 2024.1.6. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.5...2024.1.6) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dc647300a3..f538b050e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.5" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From bf2aaa1b1830e534ba651d422545ac08a115151b Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:50:08 -0600 Subject: [PATCH 229/504] Use .equals to Compare Methods Closes gh-17143 --- .../authorization/method/aspectj/PreAuthorizeAspectTests.java | 4 ++-- .../core/annotation/UniqueSecurityAnnotationScanner.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java b/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java index d978b3c8ea..5fc9fb072c 100644 --- a/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java +++ b/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -144,7 +144,7 @@ public class PreAuthorizeAspectTests { protected void protectedMethod() { } - @PreAuthorize("hasRole('X')") + @PreAuthorize("hasRole('A')") void publicCallsPrivate() { privateMethod(); } diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java index 34cd59eff3..46c2dbbfee 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java +++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -214,7 +214,7 @@ final class UniqueSecurityAnnotationScanner extends Abstra private static Method findMethod(Method method, Class targetClass) { for (Method candidate : targetClass.getDeclaredMethods()) { - if (candidate == method) { + if (candidate.equals(method)) { return candidate; } if (isOverride(method, candidate)) { From c972de5369a1261ab674a3f5e3a80e8ce3e8cdfb Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:50:08 -0600 Subject: [PATCH 230/504] Use .equals to Compare Methods Closes gh-17143 --- .../authorization/method/aspectj/PreAuthorizeAspectTests.java | 4 ++-- .../core/annotation/UniqueSecurityAnnotationScanner.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java b/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java index d978b3c8ea..5fc9fb072c 100644 --- a/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java +++ b/aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -144,7 +144,7 @@ public class PreAuthorizeAspectTests { protected void protectedMethod() { } - @PreAuthorize("hasRole('X')") + @PreAuthorize("hasRole('A')") void publicCallsPrivate() { privateMethod(); } diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java index 32bc8ea57d..f4f5b22e51 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java +++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -267,7 +267,7 @@ final class UniqueSecurityAnnotationScanner extends Abstra private static Method findMethod(Method method, Class targetClass) { for (Method candidate : targetClass.getDeclaredMethods()) { - if (candidate == method) { + if (candidate.equals(method)) { return candidate; } if (isOverride(method, candidate)) { From cae3467a8d5fdf4ef0f5c2343d48aa9c48445be2 Mon Sep 17 00:00:00 2001 From: Mark Putsiata Date: Wed, 23 Apr 2025 22:39:22 +0300 Subject: [PATCH 231/504] Improve AbstractPreAuthenticatedProcessingFilter docs Clarify misleading SecurityContextRepository setter documentation. Note that AbstractPreAuthenticatedProcessingFilter saves the SecurityContext upon successful authentication, and this behavior can be customized via the setSecurityContextRepository setter. Closes gh-14137 Signed-off-by: Mark Putsiata --- .../AbstractPreAuthenticatedProcessingFilter.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java index fb09d39e5d..21c7f95f64 100755 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,6 +79,10 @@ import org.springframework.web.filter.GenericFilterBean; * raised by the AuthenticationManager will the be re-thrown. Note that this will * not affect cases where the principal returned by {@link #getPreAuthenticatedPrincipal} * is null, when the chain will still proceed as normal. + *

+ * The filter saves the {@link SecurityContext} using the configured + * {@link SecurityContextRepository}, which can be set via + * {@link #setSecurityContextRepository}. * * @author Luke Taylor * @author Ruud Senden @@ -253,8 +257,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi /** * Sets the {@link SecurityContextRepository} to save the {@link SecurityContext} on - * authentication success. The default action is not to save the - * {@link SecurityContext}. + * authentication success. The default action is to save the {@link SecurityContext} + * in {@link HttpSession} using {@link HttpSessionSecurityContextRepository}. * @param securityContextRepository the {@link SecurityContextRepository} to use. * Cannot be null. */ From 3fbcd5f62aae4dfe9a6d39d472d95ad5b29dbb18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 May 2025 15:53:05 +0000 Subject: [PATCH 232/504] Release 6.4.6 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5ba0129aa5..4846870c71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.6-SNAPSHOT +version=6.4.6 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 0fd0e9335ae3a6ff3538045d098dd6b94679d99e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 May 2025 15:53:05 +0000 Subject: [PATCH 233/504] Release 6.5.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 88de36ef8d..ea1fdc0efa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0-SNAPSHOT +version=6.5.0 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 4a2953fa5b60c5b79165d62bbed7ee02464adbc0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 May 2025 16:33:25 +0000 Subject: [PATCH 234/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4846870c71..2d5886cf13 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.6 +version=6.4.7-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From b2576583e2aec2f4e7e5b46b7f3b40c0e9a26e99 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 May 2025 16:33:39 +0000 Subject: [PATCH 235/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ea1fdc0efa..50aca0de35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.0 +version=6.5.1-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From e772025646276876e12f080c6cb53b02818ee71c Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 19 May 2025 11:18:23 -0600 Subject: [PATCH 236/504] Update What's New in 6.5 --- docs/modules/ROOT/pages/whats-new.adoc | 44 ++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index a75c999dd4..3614b65f8f 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -3,11 +3,7 @@ Spring Security 6.5 provides a number of new features. Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix. - -== New Features - -* Support for automatic context-propagation with Micrometer (https://github.com/spring-projects/spring-security/issues/16665[gh-16665]) -* OAuth 2.0 Demonstrating Proof of Possession (DPoP) (https://github.com/spring-projects/spring-security/pull/16574[gh-16574]) +Given that this is the last minor release in the 6.x generation, please consider reading the https://docs.spring.io/spring-security/reference/6.5-SNAPSHOT/migration-7/index.html[Prepare for the 7.0 Migration Guide]. == Breaking Changes @@ -16,10 +12,46 @@ Below are the highlights of the release, or you can view https://github.com/spri The `security.security.reached.filter.section` key name was corrected to `spring.security.reached.filter.section`. Note that this may affect reports that operate on this key name. -== OAuth +== New Features +* https://github.com/spring-projects/spring-security/issues/16665[gh-16665] - Support for automatic context-propagation with Micrometer +* https://github.com/spring-projects/spring-security/pull/16574[gh-16574] - OAuth 2.0 Demonstrating Proof of Possession (DPoP) + +== Core + +* https://github.com/spring-projects/spring-security/issues/16444[gh-16444] - Add `Authentication` request to ``AuthenticationException``s +* https://github.com/spring-projects/spring-security/issues/16291[gh-16291] - Improve error messaging for impossible authorization configurations + +== Messaging + +* https://github.com/spring-projects/spring-security/pull/16635[gh-16635] - Add `PathPatternMessageMatcher` +* https://github.com/spring-projects/spring-security/issues/16766[gh-16766] - Add `matcher` support to `MessageMatcher` + +== OAuth 2.0 + +* https://github.com/spring-projects/spring-security/issues/16380[gh-16380] - Pick up `OAuth2AuthorizationRequestResolver` as a bean * https://github.com/spring-projects/spring-security/pull/16386[gh-16386] - Enable PKCE for confidential clients using `ClientRegistration.clientSettings.requireProofKey=true` for xref:servlet/oauth2/client/core.adoc#oauth2Client-client-registration-requireProofKey[servlet] and xref:reactive/oauth2/client/core.adoc#oauth2Client-client-registration-requireProofKey[reactive] applications * https://github.com/spring-projects/spring-security/issues/16913[gh-16913] - Prepare OAuth2 Client deprecations for removal in Spring Security 7 +* https://github.com/spring-projects/spring-security/pull/16574[gh-16574] - Support https://datatracker.ietf.org/doc/html/rfc9449[RFC 9499]: Dynamic Proof of Possession (DPoP) +* https://github.com/spring-projects/spring-security/issues/13185[gh-13185] - OAuth 2.0 Access Token JWT Profile Support (RFC 9068) - https://docs.spring.io/spring-security/reference/6.5-SNAPSHOT/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-validation-rfc9068[(docs)] +* https://github.com/spring-projects/spring-security/pull/16682[gh-16682] - Add `JwtAudienceValidator` +* https://github.com/spring-projects/spring-security/issues/16672[gh-16672] - Add `JwtTypeValidator` + +== SAML 2.0 + +* https://github.com/spring-projects/spring-security/issues/16915[gh-16915] - Simplify support for Response Validation +* https://github.com/spring-projects/spring-security/issues/15578[gh-15578] - Simplify support for Assertion Validation, including support for a custom set of validators +* https://github.com/spring-projects/spring-security/issues/12136[gh-12136] - Simplify support for Response Authentication Conversion, including support for principals not in `` +* https://github.com/spring-projects/spring-security/issues/14793[gh-14793] - Add RelayState-based `` repository + +== Web + +* https://github.com/spring-projects/spring-security/pull/16502[gh-16502] - Add `HttpStatusAccessDeniedHandler` +* https://github.com/spring-projects/spring-security/issues/16059[gh-16059] Add support for `ModelAndView` and +* `ResponseEntity` to `@AuthorizeReturnObject` +* https://github.com/spring-projects/spring-security/issues/16429[gh-16429] - Replace `MvcRequestMatcher` and `AntPathRequestMatcher` with `PathPatternRequestMatcher` +* https://github.com/spring-projects/spring-security/issues/16793[gh-16793] - Add support for `AuthenticationConverter` to `AbstractAuthenticationProcessingFilter` +* https://github.com/spring-projects/spring-security/issues/16678[gh-16678] - Simplify redirect-to-HTTPS support == WebAuthn From 5da31ab8a858c503132d324e442bf36ff783a881 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 20 May 2025 15:23:17 -0500 Subject: [PATCH 237/504] Use spring-io/codeql-actions --- .github/workflows/codeql.yml | 79 +++--------------------------------- 1 file changed, 6 insertions(+), 73 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4c98186dd3..60b01f76f1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,80 +1,13 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL Advanced" on: - push: # run if we update the workflow + push: + pull_request: workflow_dispatch: schedule: - - cron: '39 13 * * 4' + # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule + - cron: '0 5 * * *' jobs: - analyze: - name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ubuntu-latest - permissions: - # required for all workflows - security-events: write - - # required to fetch internal or private CodeQL packs - packages: read - - # only required for workflows in private repositories - actions: read - contents: read - - strategy: - fail-fast: false - matrix: - include: - - language: actions - build-mode: none - # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Add any setup steps before running the `github/codeql-action/init` action. - # This includes steps like installing compilers or runtimes (`actions/setup-node` - # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - queries: security-extended,security-and-quality - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + codeql-analysis-call: + uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1 From a4cd6f4278d04535f7029bc84ebd1a2bbff8c1f6 Mon Sep 17 00:00:00 2001 From: Gurunathan <129361658+Gurunathan16@users.noreply.github.com> Date: Mon, 19 May 2025 19:32:12 +0530 Subject: [PATCH 238/504] Advise Overriding equals() and hashCode() in UserDetails Implementations This commit adds a documentation note explaining the importance of overriding equals() and hashCode() in custom UserDetails implementations. The default SessionRegistryImpl in Spring Security uses an in-memory ConcurrentMap>, Map to associate principals with sessions. If a custom UserDetails class does not properly override equals() and hashCode(), user sessions may not be tracked or matched correctly. I believe this helps developers avoid subtle session management issues when implementing custom authentication logic. Signed-off-by: Gurunathan <129361658+Gurunathan16@users.noreply.github.com> --- .../pages/servlet/authentication/session-management.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc b/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc index f269c960bc..a0bd2dd526 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc @@ -534,6 +534,13 @@ public class MaximumSessionsPreventLoginTests { If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly. You can try it using the {gh-samples-url}/servlet/spring-boot/java/session-management/maximum-sessions-prevent-login[Maximum Sessions Prevent Login sample]. +[NOTE] +===== +If you are using a custom implementation of `UserDetails`, ensure you override the **equals()** and **hashCode()** methods. +The default `SessionRegistry` implementation in Spring Security relies on an in-memory Map that uses these methods to correctly identify and manage user sessions. +Failing to override them may lead to issues where session tracking and user comparison behave unexpectedly. +===== + == Detecting Timeouts Sessions expire on their own, and there is nothing that needs to be done to ensure that a security context gets removed. From 86acba9d22edce99dba82f4f7dbf97a63b3e568f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 03:51:49 +0000 Subject: [PATCH 239/504] Bump io-spring-javaformat from 0.0.43 to 0.0.45 Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 02e6579a33..9c405db07d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.43" +io-spring-javaformat = "0.0.45" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From e77388ca162ac728715edd979f84d0ea7d2d8abe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 03:29:30 +0000 Subject: [PATCH 240/504] Bump io-spring-javaformat from 0.0.43 to 0.0.45 Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 273a381b3f..3ca108e9b2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.43" +io-spring-javaformat = "0.0.45" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From b5126f54bcf54924aea918ae19b998d46095838c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 03:59:48 +0000 Subject: [PATCH 241/504] Bump io-spring-javaformat from 0.0.43 to 0.0.45 Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f538b050e1..04b1cfa6b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.43" +io-spring-javaformat = "0.0.45" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From b3340536dc645ac5083975a8bddcddb31e97e271 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 03:48:17 +0000 Subject: [PATCH 242/504] Bump io-spring-javaformat from 0.0.43 to 0.0.45 Bumps `io-spring-javaformat` from 0.0.43 to 0.0.45. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.43 to 0.0.45 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.43...v0.0.45) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.45 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d99094e4e9..3b86a9aa10 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.43" +io-spring-javaformat = "0.0.45" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From c46f263483fb48372246680252fc211f3c04241a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 03:47:59 +0000 Subject: [PATCH 243/504] Bump org.hibernate.orm:hibernate-core from 7.0.0.CR2 to 7.0.0.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.0.CR2 to 7.0.0.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.0.CR2...7.0.0) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.0.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3b86a9aa10..6a16532177 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.CR2" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 4048b2bd7d4c7cbe338294609814be3b6deb9c9d Mon Sep 17 00:00:00 2001 From: Andrey Litvitski Date: Fri, 16 May 2025 15:29:37 +0300 Subject: [PATCH 244/504] Use `HttpStatus` in BackChannel Logout Filters Closes gh-17125 Signed-off-by: Andrey Litvitski --- .../config/web/server/OidcBackChannelLogoutWebFilter.java | 7 ++++--- .../web/server/OidcBackChannelServerLogoutHandler.java | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutWebFilter.java b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutWebFilter.java index 8f1788c498..4b1e0c125d 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutWebFilter.java +++ b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutWebFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,12 @@ package org.springframework.security.config.web.server; import java.util.Collections; -import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.codec.EncoderHttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter; @@ -48,6 +48,7 @@ import org.springframework.web.server.WebFilterChain; * A filter for the Client-side OIDC Back-Channel Logout endpoint * * @author Josh Cummings + * @author Andrey Litvitski * @since 6.2 * @see OIDC Back-Channel Logout @@ -107,7 +108,7 @@ class OidcBackChannelLogoutWebFilter implements WebFilter { private Mono handleAuthenticationFailure(ServerWebExchange exchange, Exception ex) { this.logger.debug("Failed to process OIDC Back-Channel Logout", ex); - exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST); + exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value()); return this.errorHttpMessageConverter.write(Mono.just(oauth2Error(ex)), ResolvableType.forClass(Object.class), ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(), exchange.getResponse(), Collections.emptyMap()); diff --git a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelServerLogoutHandler.java b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelServerLogoutHandler.java index c0c1e73bc6..47aac17024 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelServerLogoutHandler.java +++ b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelServerLogoutHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,13 +22,13 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.codec.EncoderHttpMessageWriter; @@ -54,6 +54,7 @@ import org.springframework.web.util.UriComponentsBuilder; * Back-Channel Logout Token and invalidates each one. * * @author Josh Cummings + * @author Andrey Litvitski * @since 6.2 * @see OIDC Back-Channel Logout @@ -154,7 +155,7 @@ final class OidcBackChannelServerLogoutHandler implements ServerLogoutHandler { } private Mono handleLogoutFailure(ServerWebExchange exchange, OAuth2Error error) { - exchange.getResponse().setRawStatusCode(HttpServletResponse.SC_BAD_REQUEST); + exchange.getResponse().setRawStatusCode(HttpStatus.BAD_REQUEST.value()); return this.errorHttpMessageConverter.write(Mono.just(error), ResolvableType.forClass(Object.class), ResolvableType.forClass(Object.class), MediaType.APPLICATION_JSON, exchange.getRequest(), exchange.getResponse(), Collections.emptyMap()); From 47338f7e567560b57d073e41ae771f8654e24294 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 22 May 2025 12:29:05 -0600 Subject: [PATCH 245/504] Remove Conflict Markers --- gradle.properties | 9 --------- 1 file changed, 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2402e4c544..19a07278b1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,17 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -<<<<<<< HEAD springBootVersion=4.0.0-SNAPSHOT version=7.0.0-SNAPSHOT -======= -springBootVersion=3.3.3 -<<<<<<< HEAD -version=6.5.1-SNAPSHOT -======= -version=6.4.7-SNAPSHOT ->>>>>>> origin/6.4.x ->>>>>>> 6.5.x samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From d2d2b97b7d9651d655815d730a4f78a2c2db4de1 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 22 May 2025 12:31:40 -0600 Subject: [PATCH 246/504] Remove Conflict Markers --- gradle.properties | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index ebaaff90bc..50aca0de35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,11 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -<<<<<<< HEAD version=6.5.1-SNAPSHOT -======= -version=6.4.7-SNAPSHOT ->>>>>>> origin/6.4.x samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 0fecaf492419a78b58ad91a86953b74fc6e19b31 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 22 May 2025 14:47:37 -0500 Subject: [PATCH 247/504] Add include-code extension setup for docs Closes gh-17160 --- docs/antora.yml | 2 ++ docs/modules/ROOT/examples/docs-src | 1 + docs/spring-security-docs.gradle | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 120000 docs/modules/ROOT/examples/docs-src diff --git a/docs/antora.yml b/docs/antora.yml index 571640b91d..02262db72e 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -16,3 +16,5 @@ asciidoc: gh-old-samples-url: 'https://github.com/spring-projects/spring-security/tree/5.4.x/samples' gh-samples-url: "https://github.com/spring-projects/spring-security-samples/tree/{gh-tag}" gh-url: "https://github.com/spring-projects/spring-security/tree/{gh-tag}" + include-java: 'example$docs-src/test/java/org/springframework/security/docs' + include-kotlin: 'example$docs-src/test/kotlin/org/springframework/security/kt/docs' diff --git a/docs/modules/ROOT/examples/docs-src b/docs/modules/ROOT/examples/docs-src new file mode 120000 index 0000000000..dabb0e15a9 --- /dev/null +++ b/docs/modules/ROOT/examples/docs-src @@ -0,0 +1 @@ +../../../src \ No newline at end of file diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index 0a1f98e022..ec459fc115 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -1,7 +1,10 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' id 'io.spring.convention.repository' + id 'kotlin' } apply plugin: 'io.spring.convention.docs' @@ -33,10 +36,23 @@ tasks.register("generateAntoraResources") { dependencies { testImplementation platform(project(':spring-security-dependencies')) + testImplementation project(':spring-security-config') + testImplementation project(path : ':spring-security-config', configuration : 'tests') + testImplementation project(':spring-security-test') testImplementation 'com.unboundid:unboundid-ldapsdk' testImplementation libs.webauthn4j.core + testImplementation 'org.jetbrains.kotlin:kotlin-reflect' + testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' testImplementation 'org.apache.directory.server:apacheds-core' testImplementation 'org.springframework:spring-core' + testImplementation 'org.springframework:spring-test' + + testImplementation 'org.springframework:spring-webmvc' + testImplementation 'jakarta.servlet:jakarta.servlet-api' + testImplementation "org.junit.jupiter:junit-jupiter-api" + testImplementation "org.junit.jupiter:junit-jupiter-params" + testImplementation "org.junit.jupiter:junit-jupiter-engine" + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } def generateAttributes() { @@ -78,3 +94,16 @@ def resolvedVersions(Configuration configuration) { .resolvedArtifacts .collectEntries { [(it.name + '-version'): it.moduleVersion.id.version] } } + +test { + useJUnitPlatform() +} + +tasks.withType(KotlinCompile).configureEach { + kotlinOptions { + languageVersion = "1.7" + apiVersion = "1.7" + freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"] + jvmTarget = "17" + } +} From 6eee256e12663a5465be6fceffe0b75178f23c37 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 22 May 2025 14:57:13 -0500 Subject: [PATCH 248/504] Demonstrate include-code usage Closes gh-17161 --- .../ROOT/pages/servlet/architecture.adoc | 25 +---------- .../FilterChainUsage.java | 42 +++++++++++++++++++ .../servletfiltersreview/FilterChainUsage.kt | 37 ++++++++++++++++ 3 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 docs/src/test/java/org/springframework/security/docs/servlet/servletfiltersreview/FilterChainUsage.java create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/servletfiltersreview/FilterChainUsage.kt diff --git a/docs/modules/ROOT/pages/servlet/architecture.adoc b/docs/modules/ROOT/pages/servlet/architecture.adoc index 8b1183064b..7bba33945d 100644 --- a/docs/modules/ROOT/pages/servlet/architecture.adoc +++ b/docs/modules/ROOT/pages/servlet/architecture.adoc @@ -29,30 +29,7 @@ In this case, the `Filter` typically writes the `HttpServletResponse`. The power of the `Filter` comes from the `FilterChain` that is passed into it. .`FilterChain` Usage Example -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { - // do something before the rest of the application - chain.doFilter(request, response); // invoke the rest of the application - // do something after the rest of the application -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { - // do something before the rest of the application - chain.doFilter(request, response) // invoke the rest of the application - // do something after the rest of the application -} ----- -====== +include-code::./FilterChainUsage[tag=dofilter,indent=0] Since a `Filter` impacts only downstream `Filter` instances and the `Servlet`, the order in which each `Filter` is invoked is extremely important. diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/servletfiltersreview/FilterChainUsage.java b/docs/src/test/java/org/springframework/security/docs/servlet/servletfiltersreview/FilterChainUsage.java new file mode 100644 index 0000000000..702e73c08a --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/servletfiltersreview/FilterChainUsage.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.servletfiltersreview; + +import java.io.IOException; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; + +/** + * Demos FilterChain Usage. + * @author Rob Winch + */ +public class FilterChainUsage implements Filter { + + // tag::dofilter[] + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + // do something before the rest of the application + chain.doFilter(request, response); // invoke the rest of the application + // do something after the rest of the application + } + // end::dofilter[] +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/servletfiltersreview/FilterChainUsage.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/servletfiltersreview/FilterChainUsage.kt new file mode 100644 index 0000000000..b35a0b29c1 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/servletfiltersreview/FilterChainUsage.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.servlet.servletfiltersreview + +import jakarta.servlet.* +import java.io.IOException + +/** + * Demos FilterChain Usage. + * @author Rob Winch + */ +class FilterChainUsage : Filter { + + // tag::dofilter[] + @Throws(IOException::class, ServletException::class) + override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain) { + // do something before the rest of the application + chain.doFilter(request, response) // invoke the rest of the application + // do something after the rest of the application + } + // end::dofilter[] + +} From ff22866c6dc35cc511aea977a6684bd99ea8c17d Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 22 May 2025 15:43:38 -0500 Subject: [PATCH 249/504] RepositoryConventionPlugin supports arbitrary repositories --- .../gradle/convention/RepositoryConventionPlugin.groovy | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy index 56fcc71e9c..266f3a5b7a 100644 --- a/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/RepositoryConventionPlugin.groovy @@ -80,6 +80,11 @@ class RepositoryConventionPlugin implements Plugin { } url = 'https://repo.spring.io/release/' } + forceMavenRepositories.findAll { it.startsWith('https://') || it.startsWith('file://') }.each { mavenUrl -> + maven { + url mavenUrl + } + } } } From 64d3397a9c373b6f1c3b28e9e56714fdb2ec1e1e Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 22 May 2025 15:44:26 -0500 Subject: [PATCH 250/504] Add netty's SNAPSHOT repository to snapshot build --- .github/workflows/continuous-integration-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index f8dd0d5584..11ca8b043f 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -39,7 +39,7 @@ jobs: toolchain: 17 with: java-version: ${{ matrix.java-version }} - test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace + test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace secrets: inherit deploy-artifacts: name: Deploy Artifacts From 50f8ad55a88136c7fd42b71f0673637ef0607bb2 Mon Sep 17 00:00:00 2001 From: universe Date: Thu, 8 May 2025 11:05:38 +0800 Subject: [PATCH 251/504] Remove Redundant Punctation in JavaDoc Signed-off-by: universe --- .../authentication/UsernamePasswordAuthenticationFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java index 9a9fd4a6dd..6984d0c6a4 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationFilter.java @@ -140,7 +140,7 @@ public class UsernamePasswordAuthenticationFilter extends AbstractAuthentication /** * Sets the parameter name which will be used to obtain the password from the login - * request.. + * request. * @param passwordParameter the parameter name. Defaults to "password". */ public void setPasswordParameter(String passwordParameter) { From c0568ea9b0d7032312741450efe715ae5b806907 Mon Sep 17 00:00:00 2001 From: Joaquin Santana Date: Fri, 16 May 2025 11:43:29 +0200 Subject: [PATCH 252/504] Log Request Mismatch Only When Mismatches Signed-off-by: Joaquin Santana --- .../security/web/header/writers/ClearSiteDataHeaderWriter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java index 231e5f6585..d7584c2851 100644 --- a/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java +++ b/web/src/main/java/org/springframework/security/web/header/writers/ClearSiteDataHeaderWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,6 +75,7 @@ public final class ClearSiteDataHeaderWriter implements HeaderWriter { if (!response.containsHeader(CLEAR_SITE_DATA_HEADER)) { response.setHeader(CLEAR_SITE_DATA_HEADER, this.headerValue); } + return; } this.logger.debug( LogMessage.format("Not injecting Clear-Site-Data header since it did not match the requestMatcher %s", From 88369cd25287fbc54b77f2fcf2d42020c6a7f6e5 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Thu, 22 May 2025 10:55:51 +0700 Subject: [PATCH 253/504] Polish Signed-off-by: Tran Ngoc Nhan --- .../security/provisioning/JdbcUserDetailsManager.java | 2 ++ .../provisioning/JdbcUserDetailsManagerTests.java | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java index 5bd8aecdf3..c521af1d91 100644 --- a/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java @@ -605,6 +605,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl * set this to {@code true} to enable password updates. * @param enableUpdatePassword {@code true} to enable password updates, {@code false} * otherwise. + * @since 7.0 */ public void setEnableUpdatePassword(boolean enableUpdatePassword) { this.enableUpdatePassword = enableUpdatePassword; @@ -626,6 +627,7 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl /** * Conditionally updates password based on the setting from * {@link #setEnableUpdatePassword(boolean)}. {@inheritDoc} + * @since 7.0 */ @Override public UserDetails updatePassword(UserDetails user, String newPassword) { diff --git a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java index 3f7962e6f4..adb03ee9e8 100644 --- a/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java @@ -285,10 +285,9 @@ public class JdbcUserDetailsManagerTests { } @Test - @SuppressWarnings("unchecked") public void createGroupInsertsCorrectData() { this.manager.createGroup("TEST_GROUP", AuthorityUtils.createAuthorityList("ROLE_X", "ROLE_Y")); - List roles = this.template.queryForList("select ga.authority from groups g, group_authorities ga " + List roles = this.template.queryForList("select ga.authority from groups g, group_authorities ga " + "where ga.group_id = g.id " + "and g.group_name = 'TEST_GROUP'"); assertThat(roles).hasSize(2); } @@ -367,7 +366,7 @@ public class JdbcUserDetailsManagerTests { // SEC-2166 @Test - public void createNewAuthenticationUsesNullPasswordToKeepPassordsSave() { + public void createNewAuthenticationUsesNullPasswordToKeepPasswordSave() { insertJoe(); UsernamePasswordAuthenticationToken currentAuth = UsernamePasswordAuthenticationToken.authenticated("joe", null, AuthorityUtils.createAuthorityList("ROLE_USER")); @@ -443,9 +442,9 @@ public class JdbcUserDetailsManagerTests { this.cache.putUserInCache(joe); } - private class MockUserCache implements UserCache { + private static class MockUserCache implements UserCache { - private Map cache = new HashMap<>(); + private final Map cache = new HashMap<>(); @Override public UserDetails getUserFromCache(String username) { From 8e2067bb3ead20e1ff3bb00def1adc0966249e71 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Thu, 22 May 2025 10:56:14 +0700 Subject: [PATCH 254/504] Remove deprecated `MemberCategory#DECLARED_FIELDS` Issue gh-16889 Signed-off-by: Tran Ngoc Nhan --- .../aot/hint/AuthorizeReturnObjectHintsRegistrar.java | 4 ++-- .../security/aot/hint/CoreSecurityRuntimeHints.java | 4 ++-- .../security/aot/hint/CoreSecurityRuntimeHintsTests.java | 6 +++--- .../security/test/aot/hint/WebTestUtilsRuntimeHints.java | 8 ++++---- .../test/aot/hint/WebTestUtilsRuntimeHintsTests.java | 8 ++++---- .../security/web/aot/hint/WebMvcSecurityRuntimeHints.java | 4 ++-- .../web/aot/hint/WebMvcSecurityRuntimeHintsTests.java | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java b/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java index 0c430160b7..fb1bf28483 100644 --- a/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java +++ b/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -122,7 +122,7 @@ public final class AuthorizeReturnObjectHintsRegistrar implements SecurityHintsR .registerType(clazz, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS) .registerType(proxied, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, - MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS); + MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS); } } diff --git a/core/src/main/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHints.java b/core/src/main/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHints.java index 833b6d114a..2ac11b0f87 100644 --- a/core/src/main/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHints.java +++ b/core/src/main/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,7 +79,7 @@ class CoreSecurityRuntimeHints implements RuntimeHintsRegistrar { .registerTypes( List.of(TypeReference.of(SecurityExpressionOperations.class), TypeReference.of(SecurityExpressionRoot.class)), - (builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS, + (builder) -> builder.withMembers(MemberCategory.ACCESS_DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_METHODS)); } diff --git a/core/src/test/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHintsTests.java b/core/src/test/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHintsTests.java index 7c4eb4615e..f7e0956887 100644 --- a/core/src/test/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHintsTests.java +++ b/core/src/test/java/org/springframework/security/aot/hint/CoreSecurityRuntimeHintsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ class CoreSecurityRuntimeHintsTests { void securityExpressionOperationsHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(SecurityExpressionOperations.class) - .withMemberCategories(MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_METHODS)) + .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_METHODS)) .accepts(this.hints); } @@ -89,7 +89,7 @@ class CoreSecurityRuntimeHintsTests { void securityExpressionRootHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(SecurityExpressionRoot.class) - .withMemberCategories(MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_METHODS)) + .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS, MemberCategory.INVOKE_DECLARED_METHODS)) .accepts(this.hints); } diff --git a/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java b/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java index 9b098dd863..bb89f19f3d 100644 --- a/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java +++ b/test/src/main/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,12 +58,12 @@ class WebTestUtilsRuntimeHints implements RuntimeHintsRegistrar { } private void registerCsrfTokenRepositoryHints(RuntimeHints hints) { - hints.reflection().registerType(CsrfFilter.class, MemberCategory.DECLARED_FIELDS); + hints.reflection().registerType(CsrfFilter.class, MemberCategory.ACCESS_DECLARED_FIELDS); } private void registerSecurityContextRepositoryHints(RuntimeHints hints) { - hints.reflection().registerType(SecurityContextPersistenceFilter.class, MemberCategory.DECLARED_FIELDS); - hints.reflection().registerType(SecurityContextHolderFilter.class, MemberCategory.DECLARED_FIELDS); + hints.reflection().registerType(SecurityContextPersistenceFilter.class, MemberCategory.ACCESS_DECLARED_FIELDS); + hints.reflection().registerType(SecurityContextHolderFilter.class, MemberCategory.ACCESS_DECLARED_FIELDS); } } diff --git a/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java b/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java index 6fb662dca3..672e3ed8f4 100644 --- a/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java +++ b/test/src/test/java/org/springframework/security/test/aot/hint/WebTestUtilsRuntimeHintsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,21 +72,21 @@ class WebTestUtilsRuntimeHintsTests { void csrfFilterHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(CsrfFilter.class) - .withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(this.hints); + .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS)).accepts(this.hints); } @Test void securityContextPersistenceFilterHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(SecurityContextPersistenceFilter.class) - .withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(this.hints); + .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS)).accepts(this.hints); } @Test void securityContextHolderFilterHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(SecurityContextHolderFilter.class) - .withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(this.hints); + .withMemberCategories(MemberCategory.ACCESS_DECLARED_FIELDS)).accepts(this.hints); } } diff --git a/web/src/main/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHints.java b/web/src/main/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHints.java index 86df3618f2..347b7edc8a 100644 --- a/web/src/main/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHints.java +++ b/web/src/main/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ class WebMvcSecurityRuntimeHints implements RuntimeHintsRegistrar { public void registerHints(RuntimeHints hints, ClassLoader classLoader) { hints.reflection() .registerType(WebSecurityExpressionRoot.class, (builder) -> builder - .withMembers(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS)); + .withMembers(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS)); hints.reflection() .registerType( TypeReference diff --git a/web/src/test/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHintsTests.java b/web/src/test/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHintsTests.java index 180d10db48..5e0a9fcd4f 100644 --- a/web/src/test/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHintsTests.java +++ b/web/src/test/java/org/springframework/security/web/aot/hint/WebMvcSecurityRuntimeHintsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ class WebMvcSecurityRuntimeHintsTests { void webSecurityExpressionRootHasHints() { assertThat(RuntimeHintsPredicates.reflection() .onType(WebSecurityExpressionRoot.class) - .withMemberCategories(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS)) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS)) .accepts(this.hints); } From 9ba5c7b2ce98283a77d67d970bbfa4d2032fde34 Mon Sep 17 00:00:00 2001 From: John Niang Date: Thu, 8 May 2025 11:44:47 +0800 Subject: [PATCH 255/504] Add SwitchUserGrantedAuthority to Web Jackson Module Closes gh-17041 Signed-off-by: John Niang --- .../SwitchUserGrantedAuthorityMixIn.java | 3 +- .../web/jackson2/WebJackson2Module.java | 13 ++++-- .../SwitchUserGrantedAuthorityMixInTests.java | 46 +++++++++++++++---- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java b/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java index 4fff7ffdc4..f61b8a05bf 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.security.web.authentication.switchuser.SwitchUserGran * * @author Markus Heiden * @since 6.3 + * @see WebJackson2Module * @see WebServletJackson2Module * @see org.springframework.security.jackson2.SecurityJackson2Modules */ diff --git a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java index 87daedcc40..b8cee4fee0 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,16 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; +import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority; import org.springframework.security.web.csrf.DefaultCsrfToken; /** * Jackson module for spring-security-web. This module register - * {@link DefaultCsrfTokenMixin} and {@link PreAuthenticatedAuthenticationTokenMixin}. If - * no default typing enabled by default then it'll enable it because typing info is needed - * to properly serialize/deserialize objects. In order to use this module just add this - * module into your ObjectMapper configuration. + * {@link DefaultCsrfTokenMixin}, {@link PreAuthenticatedAuthenticationTokenMixin} and + * {@link SwitchUserGrantedAuthorityMixIn}. If no default typing enabled by default then + * it'll enable it because typing info is needed to properly serialize/deserialize + * objects. In order to use this module just add this module into your ObjectMapper + * configuration. * *

  *     ObjectMapper mapper = new ObjectMapper();
@@ -53,6 +55,7 @@ public class WebJackson2Module extends SimpleModule {
 		context.setMixInAnnotations(DefaultCsrfToken.class, DefaultCsrfTokenMixin.class);
 		context.setMixInAnnotations(PreAuthenticatedAuthenticationToken.class,
 				PreAuthenticatedAuthenticationTokenMixin.class);
+		context.setMixInAnnotations(SwitchUserGrantedAuthority.class, SwitchUserGrantedAuthorityMixIn.class);
 	}
 
 }
diff --git a/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java b/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java
index 703811658c..70bba02513 100644
--- a/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java
+++ b/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,14 +16,20 @@
 
 package org.springframework.security.web.jackson2;
 
+import java.util.stream.Stream;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.skyscreamer.jsonassert.JSONAssert;
 
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.jackson2.AbstractMixinTests;
+import org.springframework.security.jackson2.CoreJackson2Module;
+import org.springframework.security.jackson2.SecurityJackson2Modules;
 import org.springframework.security.jackson2.SimpleGrantedAuthorityMixinTests;
 import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority;
 
@@ -33,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
  * @author Markus Heiden
  * @since 6.3
  */
-public class SwitchUserGrantedAuthorityMixInTests extends AbstractMixinTests {
+public class SwitchUserGrantedAuthorityMixInTests {
 
 	// language=JSON
 	private static final String SWITCH_JSON = """
@@ -53,22 +59,42 @@ public class SwitchUserGrantedAuthorityMixInTests extends AbstractMixinTests {
 
 	private Authentication source;
 
+	static Stream mappers() {
+		ObjectMapper securityJackson2ModulesMapper = new ObjectMapper();
+		ClassLoader classLoader = SwitchUserGrantedAuthorityMixInTests.class.getClassLoader();
+		securityJackson2ModulesMapper.registerModules(SecurityJackson2Modules.getModules(classLoader));
+
+		ObjectMapper webJackson2ModuleMapper = new ObjectMapper();
+		webJackson2ModuleMapper.registerModule(new CoreJackson2Module());
+		webJackson2ModuleMapper.registerModule(new WebJackson2Module());
+
+		ObjectMapper webServletJackson2ModuleMapper = new ObjectMapper();
+		webServletJackson2ModuleMapper.registerModule(new CoreJackson2Module());
+		webServletJackson2ModuleMapper.registerModule(new WebServletJackson2Module());
+
+		return Stream.of(Arguments.of(securityJackson2ModulesMapper), Arguments.of(webJackson2ModuleMapper),
+				Arguments.of(webServletJackson2ModuleMapper));
+	}
+
 	@BeforeEach
 	public void setUp() {
 		this.source = new UsernamePasswordAuthenticationToken("principal", "credentials",
 				AuthorityUtils.createAuthorityList("ROLE_USER"));
 	}
 
-	@Test
-	public void serializeWhenPrincipalCredentialsAuthoritiesThenSuccess() throws Exception {
+	@ParameterizedTest
+	@MethodSource("mappers")
+	public void serializeWhenPrincipalCredentialsAuthoritiesThenSuccess(ObjectMapper mapper) throws Exception {
 		SwitchUserGrantedAuthority expected = new SwitchUserGrantedAuthority("switched", this.source);
-		String serializedJson = this.mapper.writeValueAsString(expected);
+		String serializedJson = mapper.writeValueAsString(expected);
 		JSONAssert.assertEquals(SWITCH_JSON, serializedJson, true);
 	}
 
-	@Test
-	public void deserializeWhenSourceIsUsernamePasswordAuthenticationTokenThenSuccess() throws Exception {
-		SwitchUserGrantedAuthority deserialized = this.mapper.readValue(SWITCH_JSON, SwitchUserGrantedAuthority.class);
+	@ParameterizedTest
+	@MethodSource("mappers")
+	public void deserializeWhenSourceIsUsernamePasswordAuthenticationTokenThenSuccess(ObjectMapper mapper)
+			throws Exception {
+		SwitchUserGrantedAuthority deserialized = mapper.readValue(SWITCH_JSON, SwitchUserGrantedAuthority.class);
 		assertThat(deserialized).isNotNull();
 		assertThat(deserialized.getAuthority()).isEqualTo("switched");
 		assertThat(deserialized.getSource()).isEqualTo(this.source);

From f4b8e2421a202575c7654bf2adef5c5b6c651383 Mon Sep 17 00:00:00 2001
From: Max Batischev 
Date: Tue, 13 May 2025 16:00:59 +0300
Subject: [PATCH 256/504] Add Support Credentialless COEP Header

Closes gh-16991

Signed-off-by: Max Batischev 
---
 .../springframework/security/config/spring-security-7.0.rnc | 2 +-
 .../springframework/security/config/spring-security-7.0.xsd | 1 +
 .../writers/CrossOriginEmbedderPolicyHeaderWriter.java      | 6 ++++--
 .../CrossOriginEmbedderPolicyServerHttpHeadersWriter.java   | 6 ++++--
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc
index ec51246b6f..15d15b191b 100644
--- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc
+++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc
@@ -1308,7 +1308,7 @@ cross-origin-embedder-policy =
 	element cross-origin-embedder-policy {cross-origin-embedder-policy-options.attlist,empty}
 cross-origin-embedder-policy-options.attlist &=
 	## The policies for the Cross-Origin-Embedder-Policy header.
-	attribute policy {"unsafe-none","require-corp"}?
+	attribute policy {"unsafe-none","require-corp", "credentialless"}?
 
 cross-origin-resource-policy =
 	## Adds support for Cross-Origin-Resource-Policy header
diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd
index e254b8488e..34556b5549 100644
--- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd
+++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd
@@ -3668,6 +3668,7 @@
             
                
                
+               
             
          
       
diff --git a/web/src/main/java/org/springframework/security/web/header/writers/CrossOriginEmbedderPolicyHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/CrossOriginEmbedderPolicyHeaderWriter.java
index d7e2a6dde5..7d9050a8e1 100644
--- a/web/src/main/java/org/springframework/security/web/header/writers/CrossOriginEmbedderPolicyHeaderWriter.java
+++ b/web/src/main/java/org/springframework/security/web/header/writers/CrossOriginEmbedderPolicyHeaderWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2025 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,7 +58,9 @@ public final class CrossOriginEmbedderPolicyHeaderWriter implements HeaderWriter
 
 		UNSAFE_NONE("unsafe-none"),
 
-		REQUIRE_CORP("require-corp");
+		REQUIRE_CORP("require-corp"),
+
+		CREDENTIALLESS("credentialless");
 
 		private final String policy;
 
diff --git a/web/src/main/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriter.java
index 17446845dd..d1d6e72629 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/CrossOriginEmbedderPolicyServerHttpHeadersWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2025 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -61,7 +61,9 @@ public final class CrossOriginEmbedderPolicyServerHttpHeadersWriter implements S
 
 		UNSAFE_NONE("unsafe-none"),
 
-		REQUIRE_CORP("require-corp");
+		REQUIRE_CORP("require-corp"),
+
+		CREDENTIALLESS("credentialless");
 
 		private final String policy;
 

From 8612e952fec7901d3b3d5f371bbf9987c4f8922a Mon Sep 17 00:00:00 2001
From: dae won 
Date: Fri, 25 Apr 2025 20:13:56 +0900
Subject: [PATCH 257/504] Make AuthorizationProxyFactory#proxy Generic

Closes gh-16706

Signed-off-by: dae won 
---
 .../AuthorizationProxyWebConfiguration.java            |  2 +-
 .../AuthorizationProxyConfigurationTests.java          | 10 +++++-----
 .../aot/hint/AuthorizeReturnObjectHintsRegistrar.java  |  2 +-
 .../authorization/AuthorizationProxyFactory.java       |  6 ++++--
 .../method/AuthorizationAdvisorProxyFactory.java       | 10 +++++-----
 .../AuthorizationAdvisorProxyFactoryTests.java         |  2 +-
 6 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java
index 4af062ef96..62faa1a6bc 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java
@@ -51,7 +51,7 @@ class AuthorizationProxyWebConfiguration {
 			if (target instanceof ModelAndView mav) {
 				View view = mav.getView();
 				String viewName = mav.getViewName();
-				Map model = (Map) proxyFactory.proxy(mav.getModel());
+				Map model = proxyFactory.proxy(mav.getModel());
 				ModelAndView proxied = (view != null) ? new ModelAndView(view, model)
 						: new ModelAndView(viewName, model);
 				proxied.setStatus(mav.getStatus());
diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfigurationTests.java
index 254c8b0871..8a66881929 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfigurationTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyConfigurationTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@ public class AuthorizationProxyConfigurationTests {
 	@Test
 	public void proxyWhenNotPreAuthorizedThenDenies() {
 		this.spring.register(DefaultsConfig.class).autowire();
-		Toaster toaster = (Toaster) this.proxyFactory.proxy(new Toaster());
+		Toaster toaster = this.proxyFactory.proxy(new Toaster());
 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(toaster::makeToast)
 			.withMessage("Access Denied");
 		assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(toaster::extractBread)
@@ -69,7 +69,7 @@ public class AuthorizationProxyConfigurationTests {
 	@Test
 	public void proxyWhenPreAuthorizedThenAllows() {
 		this.spring.register(DefaultsConfig.class).autowire();
-		Toaster toaster = (Toaster) this.proxyFactory.proxy(new Toaster());
+		Toaster toaster = this.proxyFactory.proxy(new Toaster());
 		toaster.makeToast();
 		assertThat(toaster.extractBread()).isEqualTo("yummy");
 	}
@@ -77,7 +77,7 @@ public class AuthorizationProxyConfigurationTests {
 	@Test
 	public void proxyReactiveWhenNotPreAuthorizedThenDenies() {
 		this.spring.register(ReactiveDefaultsConfig.class).autowire();
-		Toaster toaster = (Toaster) this.proxyFactory.proxy(new Toaster());
+		Toaster toaster = this.proxyFactory.proxy(new Toaster());
 		Authentication user = TestAuthentication.authenticatedUser();
 		StepVerifier
 			.create(toaster.reactiveMakeToast().contextWrite(ReactiveSecurityContextHolder.withAuthentication(user)))
@@ -90,7 +90,7 @@ public class AuthorizationProxyConfigurationTests {
 	@Test
 	public void proxyReactiveWhenPreAuthorizedThenAllows() {
 		this.spring.register(ReactiveDefaultsConfig.class).autowire();
-		Toaster toaster = (Toaster) this.proxyFactory.proxy(new Toaster());
+		Toaster toaster = this.proxyFactory.proxy(new Toaster());
 		Authentication admin = TestAuthentication.authenticatedAdmin();
 		StepVerifier
 			.create(toaster.reactiveMakeToast().contextWrite(ReactiveSecurityContextHolder.withAuthentication(admin)))
diff --git a/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java b/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java
index fb1bf28483..cf5cd1b17e 100644
--- a/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java
+++ b/core/src/main/java/org/springframework/security/aot/hint/AuthorizeReturnObjectHintsRegistrar.java
@@ -109,7 +109,7 @@ public final class AuthorizeReturnObjectHintsRegistrar implements SecurityHintsR
 	}
 
 	private void registerProxy(RuntimeHints hints, Class clazz) {
-		Class proxied = (Class) this.proxyFactory.proxy(clazz);
+		Class proxied = this.proxyFactory.proxy(clazz);
 		if (proxied == null) {
 			return;
 		}
diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorizationProxyFactory.java b/core/src/main/java/org/springframework/security/authorization/AuthorizationProxyFactory.java
index c425db9a01..e6e1210e74 100644
--- a/core/src/main/java/org/springframework/security/authorization/AuthorizationProxyFactory.java
+++ b/core/src/main/java/org/springframework/security/authorization/AuthorizationProxyFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2025 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ package org.springframework.security.authorization;
  * A factory for wrapping arbitrary objects in authorization-related advice
  *
  * @author Josh Cummings
+ * @author daewon kim
  * @since 6.3
  * @see org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory
  */
@@ -30,11 +31,12 @@ public interface AuthorizationProxyFactory {
 	 *
 	 * 

* Please check the implementation for which kinds of objects it supports. + * @param the type of the object being proxied * @param object the object to proxy * @return the proxied object * @throws org.springframework.aop.framework.AopConfigException if a proxy cannot be * created */ - Object proxy(Object object); + T proxy(T object); } diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java index dd4abb3754..f0f3984cb7 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java @@ -172,16 +172,16 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx * @return the proxied instance */ @Override - public Object proxy(Object target) { + public T proxy(T target) { if (target == null) { return null; } if (target instanceof AuthorizationProxy proxied) { - return proxied; + return (T) proxied; } Object proxied = this.visitor.visit(this, target); if (proxied != null) { - return proxied; + return (T) proxied; } ProxyFactory factory = new ProxyFactory(target); factory.addAdvisors(this.authorizationProxy); @@ -191,7 +191,7 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx factory.addInterface(AuthorizationProxy.class); factory.setOpaque(true); factory.setProxyTargetClass(!Modifier.isFinal(target.getClass().getModifiers())); - return factory.getProxy(); + return (T) factory.getProxy(); } /** @@ -442,7 +442,7 @@ public final class AuthorizationAdvisorProxyFactory implements AuthorizationProx @SuppressWarnings("unchecked") private T proxyCast(AuthorizationProxyFactory proxyFactory, T target) { - return (T) proxyFactory.proxy(target); + return proxyFactory.proxy(target); } private Iterable proxyIterable(AuthorizationProxyFactory proxyFactory, Iterable iterable) { diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java index 93d7ee1520..3babccf147 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java +++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java @@ -335,7 +335,7 @@ public class AuthorizationAdvisorProxyFactoryTests { @Test public void setTargetVisitorIgnoreValueTypesThenIgnores() { AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); - assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> ((Integer) factory.proxy(35)).intValue()); + assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> factory.proxy(35).intValue()); factory.setTargetVisitor(TargetVisitor.defaultsSkipValueTypes()); assertThat(factory.proxy(35)).isEqualTo(35); } From fae61b942660b807eb1611af07bdb23122307050 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Thu, 8 May 2025 05:58:50 +0300 Subject: [PATCH 258/504] Propagate AccessDeniedException for Authorized Objects Returned from a Controller Closes gh-16058 Signed-off-by: Evgeniy Cheban --- .../AuthorizationProxyWebConfiguration.java | 48 +++- ...ePostMethodSecurityConfigurationTests.java | 228 ++++++++++++++++++ 2 files changed, 275 insertions(+), 1 deletion(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java index 62faa1a6bc..85fefe4f57 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java @@ -16,20 +16,30 @@ package org.springframework.security.config.annotation.method.configuration; +import java.util.List; import java.util.Map; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; +import org.springframework.security.web.util.ThrowableAnalyzer; +import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; @Configuration -class AuthorizationProxyWebConfiguration { +class AuthorizationProxyWebConfiguration implements WebMvcConfigurer { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @@ -37,6 +47,18 @@ class AuthorizationProxyWebConfiguration { return new WebTargetVisitor(); } + @Override + public void extendHandlerExceptionResolvers(List resolvers) { + for (int i = 0; i < resolvers.size(); i++) { + HandlerExceptionResolver resolver = resolvers.get(i); + if (resolver instanceof DefaultHandlerExceptionResolver) { + resolvers.add(i, new HttpMessageNotWritableAccessDeniedExceptionResolver()); + return; + } + } + resolvers.add(new HttpMessageNotWritableAccessDeniedExceptionResolver()); + } + static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor { @Override @@ -62,4 +84,28 @@ class AuthorizationProxyWebConfiguration { } + static class HttpMessageNotWritableAccessDeniedExceptionResolver implements HandlerExceptionResolver { + + final ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer(); + + @Override + public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, + Exception ex) { + // Only resolves AccessDeniedException if it occurred during serialization, + // otherwise lets the user-defined handler deal with it. + if (ex instanceof HttpMessageNotWritableException) { + Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex); + Throwable accessDeniedException = this.throwableAnalyzer + .getFirstThrowableOfType(AccessDeniedException.class, causeChain); + if (accessDeniedException != null) { + return new ModelAndView((model, req, res) -> { + throw ex; + }); + } + } + return null; + } + + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index 8eec0f1bce..fe9ccfc77e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -33,6 +33,7 @@ import io.micrometer.observation.ObservationHandler; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationTextPublisher; import jakarta.annotation.security.DenyAll; +import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.junit.jupiter.api.Test; @@ -42,6 +43,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import org.springframework.aop.Advisor; +import org.springframework.aop.Pointcut; import org.springframework.aop.config.AopConfigUtils; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.aop.support.JdkRegexpMethodPointcut; @@ -62,8 +64,11 @@ import org.springframework.context.event.EventListener; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.annotation.BusinessService; @@ -95,6 +100,7 @@ import org.springframework.security.authorization.method.MethodAuthorizationDeni import org.springframework.security.authorization.method.MethodInvocationResult; import org.springframework.security.authorization.method.PrePostTemplateDefaults; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.core.GrantedAuthorityDefaults; import org.springframework.security.config.observation.SecurityObservationSettings; import org.springframework.security.config.test.SpringTestContext; @@ -106,13 +112,24 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener; +import org.springframework.security.web.util.ThrowableAnalyzer; import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -127,6 +144,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * Tests for {@link PrePostMethodSecurityConfiguration}. @@ -148,6 +168,9 @@ public class PrePostMethodSecurityConfigurationTests { @Autowired(required = false) BusinessService businessService; + @Autowired(required = false) + MockMvc mvc; + @WithMockUser @Test public void customMethodSecurityPreAuthorizeAdminWhenRoleUserThenAccessDeniedException() { @@ -1181,6 +1204,97 @@ public class PrePostMethodSecurityConfigurationTests { } } + @Test + void getWhenPostAuthorizeAuthenticationNameMatchesThenRespondsWithOk() throws Exception { + this.spring.register(WebMvcMethodSecurityConfig.class, BasicController.class).autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/authorized-person") + .param("name", "rob") + .with(user("rob")); + // @formatter:on + this.mvc.perform(requestWithUser).andExpect(status().isOk()); + } + + @Test + void getWhenPostAuthorizeAuthenticationNameNotMatchThenRespondsWithForbidden() throws Exception { + this.spring.register(WebMvcMethodSecurityConfig.class, BasicController.class).autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/authorized-person") + .param("name", "john") + .with(user("rob")); + // @formatter:on + this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); + } + + @Test + void getWhenPostAuthorizeWithinServiceAuthenticationNameMatchesThenRespondsWithOk() throws Exception { + this.spring.register(WebMvcMethodSecurityConfig.class, BasicController.class, BasicService.class).autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/greetings/authorized-person") + .param("name", "rob") + .with(user("rob")); + // @formatter:on + MvcResult mvcResult = this.mvc.perform(requestWithUser).andExpect(status().isOk()).andReturn(); + assertThat(mvcResult.getResponse().getContentAsString()).isEqualTo("Hello: rob"); + } + + @Test + void getWhenPostAuthorizeWithinServiceAuthenticationNameNotMatchThenCustomHandlerRespondsWithForbidden() + throws Exception { + this.spring + .register(WebMvcMethodSecurityConfig.class, BasicController.class, BasicService.class, + BasicControllerAdvice.class) + .autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/greetings/authorized-person") + .param("name", "john") + .with(user("rob")); + // @formatter:on + MvcResult mvcResult = this.mvc.perform(requestWithUser).andExpect(status().isForbidden()).andReturn(); + assertThat(mvcResult.getResponse().getContentAsString()).isEqualTo(""" + {"message":"Access Denied"}\ + """); + } + + @Test + void getWhenPostAuthorizeAuthenticationNameNotMatchThenCustomHandlerRespondsWithForbidden() throws Exception { + this.spring + .register(WebMvcMethodSecurityConfig.class, BasicController.class, BasicService.class, + BasicControllerAdvice.class) + .autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/authorized-person") + .param("name", "john") + .with(user("rob")); + // @formatter:on + MvcResult mvcResult = this.mvc.perform(requestWithUser).andExpect(status().isForbidden()).andReturn(); + assertThat(mvcResult.getResponse().getContentAsString()).isEqualTo(""" + {"message":"Could not write JSON: Access Denied"}\ + """); + } + + @Test + void getWhenCustomAdvisorAuthenticationNameMatchesThenRespondsWithOk() throws Exception { + this.spring.register(WebMvcMethodSecurityCustomAdvisorConfig.class, BasicController.class).autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/authorized-person") + .param("name", "rob") + .with(user("rob")); + // @formatter:on + this.mvc.perform(requestWithUser).andExpect(status().isOk()); + } + + @Test + void getWhenCustomAdvisorAuthenticationNameNotMatchThenRespondsWithForbidden() throws Exception { + this.spring.register(WebMvcMethodSecurityCustomAdvisorConfig.class, BasicController.class).autowire(); + // @formatter:off + MockHttpServletRequestBuilder requestWithUser = get("/authorized-person") + .param("name", "john") + .with(user("rob")); + // @formatter:on + this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); + } + private static Consumer disallowBeanOverriding() { return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false); } @@ -1919,4 +2033,118 @@ public class PrePostMethodSecurityConfigurationTests { } + @EnableWebMvc + @EnableWebSecurity + @EnableMethodSecurity + static class WebMvcMethodSecurityConfig { + + } + + @EnableWebMvc + @EnableWebSecurity + @EnableMethodSecurity + static class WebMvcMethodSecurityCustomAdvisorConfig { + + @Bean + AuthorizationAdvisor customAdvisor(SecurityContextHolderStrategy strategy) { + JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut(); + pointcut.setPattern(".*AuthorizedPerson.*getName"); + return new AuthorizationAdvisor() { + @Override + public Object invoke(MethodInvocation mi) throws Throwable { + Authentication auth = strategy.getContext().getAuthentication(); + Object result = mi.proceed(); + if (auth.getName().equals(result)) { + return result; + } + throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'"); + } + + @Override + public Pointcut getPointcut() { + return pointcut; + } + + @Override + public Advice getAdvice() { + return this; + } + + @Override + public int getOrder() { + return AuthorizationInterceptorsOrder.POST_FILTER.getOrder() + 1; + } + }; + } + + } + + @RestController + static class BasicController { + + @Autowired(required = false) + BasicService service; + + @GetMapping("/greetings/authorized-person") + String getAuthorizedPersonGreeting(@RequestParam String name) { + AuthorizedPerson authorizedPerson = this.service.getAuthorizedPerson(name); + return "Hello: " + authorizedPerson.getName(); + } + + @AuthorizeReturnObject + @GetMapping(value = "/authorized-person", produces = MediaType.APPLICATION_JSON_VALUE) + AuthorizedPerson getAuthorizedPerson(@RequestParam String name) { + return new AuthorizedPerson(name); + } + + } + + @ControllerAdvice + static class BasicControllerAdvice { + + @ExceptionHandler(AccessDeniedException.class) + ResponseEntity> handleAccessDenied(AccessDeniedException ex) { + Map responseBody = Map.of("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(responseBody); + } + + @ExceptionHandler(HttpMessageNotWritableException.class) + ResponseEntity> handleHttpMessageNotWritable(HttpMessageNotWritableException ex) { + ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer(); + Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex); + Throwable t = throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain); + if (t != null) { + Map responseBody = Map.of("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(responseBody); + } + throw ex; + } + + } + + @Service + static class BasicService { + + @AuthorizeReturnObject + AuthorizedPerson getAuthorizedPerson(String name) { + return new AuthorizedPerson(name); + } + + } + + public static class AuthorizedPerson { + + final String name; + + AuthorizedPerson(String name) { + this.name = name; + } + + @PostAuthorize("returnObject == authentication.name") + public String getName() { + return this.name; + } + + } + } From 52394c1f079cc28126c801ae91f640ed37a4b44c Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 23 May 2025 15:00:01 -0600 Subject: [PATCH 259/504] Propagate Any AccessDeniedException Any time a response handler throws an exception, we want to propagate an underlying AccessDeniedException if their is one. Issue gh-16058 --- .../AuthorizationProxyWebConfiguration.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java index 85fefe4f57..be26ed3713 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java @@ -28,7 +28,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; import org.springframework.security.web.util.ThrowableAnalyzer; @@ -52,11 +51,11 @@ class AuthorizationProxyWebConfiguration implements WebMvcConfigurer { for (int i = 0; i < resolvers.size(); i++) { HandlerExceptionResolver resolver = resolvers.get(i); if (resolver instanceof DefaultHandlerExceptionResolver) { - resolvers.add(i, new HttpMessageNotWritableAccessDeniedExceptionResolver()); + resolvers.add(i, new AccessDeniedExceptionResolver()); return; } } - resolvers.add(new HttpMessageNotWritableAccessDeniedExceptionResolver()); + resolvers.add(new AccessDeniedExceptionResolver()); } static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor { @@ -84,24 +83,20 @@ class AuthorizationProxyWebConfiguration implements WebMvcConfigurer { } - static class HttpMessageNotWritableAccessDeniedExceptionResolver implements HandlerExceptionResolver { + static class AccessDeniedExceptionResolver implements HandlerExceptionResolver { final ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer(); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { - // Only resolves AccessDeniedException if it occurred during serialization, - // otherwise lets the user-defined handler deal with it. - if (ex instanceof HttpMessageNotWritableException) { - Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex); - Throwable accessDeniedException = this.throwableAnalyzer - .getFirstThrowableOfType(AccessDeniedException.class, causeChain); - if (accessDeniedException != null) { - return new ModelAndView((model, req, res) -> { - throw ex; - }); - } + Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex); + Throwable accessDeniedException = this.throwableAnalyzer + .getFirstThrowableOfType(AccessDeniedException.class, causeChain); + if (accessDeniedException != null) { + return new ModelAndView((model, req, res) -> { + throw ex; + }); } return null; } From 1a4de49977458bdc89e88c1775a2b5f9030f4299 Mon Sep 17 00:00:00 2001 From: Felix Hagemans Date: Fri, 18 Apr 2025 14:18:24 +0200 Subject: [PATCH 260/504] Create CsrfCustomizer for SPA configuration Closes gh-14149 Signed-off-by: Felix Hagemans --- .../web/configurers/CsrfConfigurer.java | 60 ++++++++++++ .../web/configurers/CsrfConfigurerTests.java | 44 +++++++++ .../ROOT/pages/servlet/exploits/csrf.adoc | 96 +------------------ 3 files changed, 109 insertions(+), 91 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java index 55c8f81ab8..833efe4e22 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java @@ -19,9 +19,11 @@ package org.springframework.security.config.annotation.web.configurers; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.function.Supplier; import io.micrometer.observation.ObservationRegistry; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationContext; import org.springframework.security.access.AccessDeniedException; @@ -34,13 +36,17 @@ import org.springframework.security.web.access.CompositeAccessDeniedHandler; import org.springframework.security.web.access.DelegatingAccessDeniedHandler; import org.springframework.security.web.access.ObservationMarkingAccessDeniedHandler; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.csrf.CsrfAuthenticationStrategy; import org.springframework.security.web.csrf.CsrfFilter; import org.springframework.security.web.csrf.CsrfLogoutHandler; +import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; import org.springframework.security.web.csrf.CsrfTokenRequestHandler; import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; import org.springframework.security.web.csrf.MissingCsrfTokenException; +import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler; import org.springframework.security.web.session.InvalidSessionStrategy; import org.springframework.security.web.util.matcher.AndRequestMatcher; @@ -48,6 +54,7 @@ import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Adds @@ -214,6 +221,21 @@ public final class CsrfConfigurer> return this; } + /** + *

+ * Sensible CSRF defaults when used in combination with a single page application. + * Creates a cookie-based token repository and a custom request handler to resolve the + * actual token value instead of the encoded token. + *

+ * @return the {@link CsrfConfigurer} for further customizations + * @since 7.0 + */ + public CsrfConfigurer spa() { + this.csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse(); + this.requestHandler = new SpaCsrfTokenRequestHandler(); + return this; + } + @SuppressWarnings("unchecked") @Override public void configure(H http) { @@ -375,4 +397,42 @@ public final class CsrfConfigurer> } + private static class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler { + + private final CsrfTokenRequestAttributeHandler plain = new CsrfTokenRequestAttributeHandler(); + + private final CsrfTokenRequestAttributeHandler xor = new XorCsrfTokenRequestAttributeHandler(); + + SpaCsrfTokenRequestHandler() { + this.xor.setCsrfRequestAttributeName(null); + } + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, Supplier csrfToken) { + /* + * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection + * of the CsrfToken when it is rendered in the response body. + */ + this.xor.handle(request, response, csrfToken); + } + + @Override + public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { + String headerValue = request.getHeader(csrfToken.getHeaderName()); + /* + * If the request contains a request header, use + * CsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies + * when a single-page application includes the header value automatically, + * which was obtained via a cookie containing the raw CsrfToken. + * + * In all other cases (e.g. if the request contains a request parameter), use + * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies + * when a server-side rendered form includes the _csrf request parameter as a + * hidden input. + */ + return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken); + } + + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java index 216579b64d..04a288078f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java @@ -93,6 +93,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -613,6 +614,37 @@ public class CsrfConfigurerTests { assertThat(cookies).isEmpty(); } + @Test + public void spaConfigForbidden() throws Exception { + this.spring.register(CsrfSpaConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class) + .autowire(); + this.mvc.perform(post("/")).andExpect(status().isForbidden()); + } + + @Test + public void spaConfigOk() throws Exception { + this.spring.register(CsrfSpaConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class) + .autowire(); + this.mvc.perform(post("/").with(csrf())).andExpect(status().isOk()); + } + + @Test + public void spaConfigDoubleSubmit() throws Exception { + this.spring.register(CsrfSpaConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class) + .autowire(); + var token = this.mvc.perform(post("/")) + .andExpect(status().isForbidden()) + .andExpect(cookie().exists("XSRF-TOKEN")) + .andReturn() + .getResponse() + .getCookie("XSRF-TOKEN"); + + this.mvc + .perform(post("/").header("X-XSRF-TOKEN", token.getValue()) + .cookie(new Cookie("XSRF-TOKEN", token.getValue()))) + .andExpect(status().isOk()); + } + @Configuration static class AllowHttpMethodsFirewallConfig { @@ -1006,6 +1038,18 @@ public class CsrfConfigurerTests { } + @Configuration + @EnableWebSecurity + static class CsrfSpaConfig { + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf(CsrfConfigurer::spa); + return http.build(); + } + + } + @Configuration @EnableWebSecurity static class HttpBasicCsrfTokenRequestHandlerConfig { diff --git a/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc b/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc index ab4af97dde..f02350dc6d 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/csrf.adoc @@ -787,48 +787,10 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // ... - .csrf((csrf) -> csrf - .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) // <1> - .csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()) // <2> - ); + .csrf((csrf) -> csrf.spa()); return http.build(); } } - -final class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler { - private final CsrfTokenRequestHandler plain = new CsrfTokenRequestAttributeHandler(); - private final CsrfTokenRequestHandler xor = new XorCsrfTokenRequestAttributeHandler(); - - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, Supplier csrfToken) { - /* - * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of - * the CsrfToken when it is rendered in the response body. - */ - this.xor.handle(request, response, csrfToken); - /* - * Render the token value to a cookie by causing the deferred token to be loaded. - */ - csrfToken.get(); - } - - @Override - public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { - String headerValue = request.getHeader(csrfToken.getHeaderName()); - /* - * If the request contains a request header, use CsrfTokenRequestAttributeHandler - * to resolve the CsrfToken. This applies when a single-page application includes - * the header value automatically, which was obtained via a cookie containing the - * raw CsrfToken. - * - * In all other cases (e.g. if the request contains a request parameter), use - * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies - * when a server-side rendered form includes the _csrf request parameter as a - * hidden input. - */ - return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken); - } -} ---- Kotlin:: @@ -846,51 +808,12 @@ class SecurityConfig { http { // ... csrf { - csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse() // <1> - csrfTokenRequestHandler = SpaCsrfTokenRequestHandler() // <2> + spa() } } return http.build() } } - -class SpaCsrfTokenRequestHandler : CsrfTokenRequestHandler { - private val plain: CsrfTokenRequestHandler = CsrfTokenRequestAttributeHandler() - private val xor: CsrfTokenRequestHandler = XorCsrfTokenRequestAttributeHandler() - - override fun handle(request: HttpServletRequest, response: HttpServletResponse, csrfToken: Supplier) { - /* - * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of - * the CsrfToken when it is rendered in the response body. - */ - xor.handle(request, response, csrfToken) - /* - * Render the token value to a cookie by causing the deferred token to be loaded. - */ - csrfToken.get() - } - - override fun resolveCsrfTokenValue(request: HttpServletRequest, csrfToken: CsrfToken): String? { - val headerValue = request.getHeader(csrfToken.headerName) - /* - * If the request contains a request header, use CsrfTokenRequestAttributeHandler - * to resolve the CsrfToken. This applies when a single-page application includes - * the header value automatically, which was obtained via a cookie containing the - * raw CsrfToken. - */ - return if (StringUtils.hasText(headerValue)) { - plain - } else { - /* - * In all other cases (e.g. if the request contains a request parameter), use - * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies - * when a server-side rendered form includes the _csrf request parameter as a - * hidden input. - */ - xor - }.resolveCsrfTokenValue(request, csrfToken) - } -} ---- XML:: @@ -899,22 +822,13 @@ XML:: ---- - - request-handler-ref="requestHandler"/> <2> + + + - - ---- ====== -<1> Configure `CookieCsrfTokenRepository` with `HttpOnly` set to `false` so the cookie can be read by the JavaScript application. -<2> Configure a custom `CsrfTokenRequestHandler` that resolves the CSRF token based on whether it is an HTTP request header (`X-XSRF-TOKEN`) or request parameter (`_csrf`). - This implementation also causes the deferred `CsrfToken` to be loaded on every request, which will return a new cookie if needed. - [[csrf-integration-javascript-mpa]] ==== Multi-Page Applications From 596449d882693c0eabef144e8fc59d68055b12f9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 27 May 2025 11:17:30 -0600 Subject: [PATCH 261/504] Polish Issue gh-14149 --- .../web/configurers/CsrfConfigurer.java | 19 ++----------------- .../web/configurers/CsrfConfigurerTests.java | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java index 833efe4e22..6188a7f056 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -397,7 +397,7 @@ public final class CsrfConfigurer> } - private static class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler { + private static final class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler { private final CsrfTokenRequestAttributeHandler plain = new CsrfTokenRequestAttributeHandler(); @@ -409,27 +409,12 @@ public final class CsrfConfigurer> @Override public void handle(HttpServletRequest request, HttpServletResponse response, Supplier csrfToken) { - /* - * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection - * of the CsrfToken when it is rendered in the response body. - */ this.xor.handle(request, response, csrfToken); } @Override public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { String headerValue = request.getHeader(csrfToken.getHeaderName()); - /* - * If the request contains a request header, use - * CsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies - * when a single-page application includes the header value automatically, - * which was obtained via a cookie containing the raw CsrfToken. - * - * In all other cases (e.g. if the request contains a request parameter), use - * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies - * when a server-side rendered form includes the _csrf request parameter as a - * hidden input. - */ return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java index 04a288078f..a37a101fbc 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 91b21663dba059005ff7432faf2aa08977f8d3d8 Mon Sep 17 00:00:00 2001 From: Ferenc Kemeny Date: Thu, 8 May 2025 22:40:47 +0200 Subject: [PATCH 262/504] Polish JwtTimestampValidatorTests This commit corrects the test that checks for both nbf and exp missing. It also adds one for just exp and on for just nbf. Issue gh-17004 Signed-off-by: Ferenc Kemeny --- .../oauth2/jwt/JwtTimestampValidatorTests.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java index 72164cf21b..272004a5ec 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java @@ -129,6 +129,23 @@ public class JwtTimestampValidatorTests { @Test public void validateWhenNeitherExpiryNorNotBeforeIsSpecifiedThenReturnsSuccessfulResult() { + Jwt jwt = TestJwts.jwt().claims((c) -> { + c.remove(JwtClaimNames.EXP); + c.remove(JwtClaimNames.NBF); + }).build(); + JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); + assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); + } + + @Test + public void validateWhenExpiryIsSpecifiedThenReturnsSuccessfulResult() { + Jwt jwt = TestJwts.jwt().claims((c) -> c.remove(JwtClaimNames.EXP)).build(); + JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); + assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); + } + + @Test + public void validateWhenNotBeforeIsSpecifiedThenReturnsSuccessfulResult() { Jwt jwt = TestJwts.jwt().claims((c) -> c.remove(JwtClaimNames.EXP)).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); From bf05b8b4307fe11fb7001aabd48835a0ffb6dea9 Mon Sep 17 00:00:00 2001 From: Ferenc Kemeny Date: Thu, 8 May 2025 22:41:36 +0200 Subject: [PATCH 263/504] Support Requiring exp and nbf in JwtTimestampsValidator Closes gh-17004 Signed-off-by: Ferenc Kemeny --- .../oauth2/jwt/JwtTimestampValidator.java | 45 +++++++++++++++---- .../jwt/JwtTimestampValidatorTests.java | 18 +++++++- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtTimestampValidator.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtTimestampValidator.java index d191b8b11a..f23dfbe4f7 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtTimestampValidator.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtTimestampValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2TokenValidator; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * An implementation of {@link OAuth2TokenValidator} for verifying claims in a Jwt-based @@ -54,6 +55,10 @@ public final class JwtTimestampValidator implements OAuth2TokenValidator { private final Duration clockSkew; + private boolean allowEmptyExpiryClaim = true; + + private boolean allowEmptyNotBeforeClaim = true; + private Clock clock = Clock.systemUTC(); /** @@ -68,30 +73,54 @@ public final class JwtTimestampValidator implements OAuth2TokenValidator { this.clockSkew = clockSkew; } + /** + * Whether to allow the {@code exp} header to be empty. The default value is + * {@code true} + * + * @since 7.0 + */ + public void setAllowEmptyExpiryClaim(boolean allowEmptyExpiryClaim) { + this.allowEmptyExpiryClaim = allowEmptyExpiryClaim; + } + + /** + * Whether to allow the {@code nbf} header to be empty. The default value is + * {@code true} + * + * @since 7.0 + */ + public void setAllowEmptyNotBeforeClaim(boolean allowEmptyNotBeforeClaim) { + this.allowEmptyNotBeforeClaim = allowEmptyNotBeforeClaim; + } + @Override public OAuth2TokenValidatorResult validate(Jwt jwt) { Assert.notNull(jwt, "jwt cannot be null"); Instant expiry = jwt.getExpiresAt(); + if (!this.allowEmptyExpiryClaim && ObjectUtils.isEmpty(expiry)) { + return createOAuth2Error("exp is required"); + } if (expiry != null) { if (Instant.now(this.clock).minus(this.clockSkew).isAfter(expiry)) { - OAuth2Error oAuth2Error = createOAuth2Error(String.format("Jwt expired at %s", jwt.getExpiresAt())); - return OAuth2TokenValidatorResult.failure(oAuth2Error); + return createOAuth2Error(String.format("Jwt expired at %s", jwt.getExpiresAt())); } } Instant notBefore = jwt.getNotBefore(); + if (!this.allowEmptyNotBeforeClaim && ObjectUtils.isEmpty(notBefore)) { + return createOAuth2Error("nbf is required"); + } if (notBefore != null) { if (Instant.now(this.clock).plus(this.clockSkew).isBefore(notBefore)) { - OAuth2Error oAuth2Error = createOAuth2Error(String.format("Jwt used before %s", jwt.getNotBefore())); - return OAuth2TokenValidatorResult.failure(oAuth2Error); + return createOAuth2Error(String.format("Jwt used before %s", jwt.getNotBefore())); } } return OAuth2TokenValidatorResult.success(); } - private OAuth2Error createOAuth2Error(String reason) { + private OAuth2TokenValidatorResult createOAuth2Error(String reason) { this.logger.debug(reason); - return new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, reason, - "https://tools.ietf.org/html/rfc6750#section-3.1"); + return OAuth2TokenValidatorResult.failure(new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, reason, + "https://tools.ietf.org/html/rfc6750#section-3.1")); } /** diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java index 272004a5ec..0d88794c0f 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,6 +158,22 @@ public class JwtTimestampValidatorTests { assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); } + @Test + public void validateWhenNotAllowEmptyExpiryClaimAndNotBeforeIsValidAndExpiryIsNotSpecifiedThenReturnsSuccessfulResult() { + Jwt jwt = TestJwts.jwt().claims((c) -> c.remove(JwtClaimNames.EXP)).notBefore(Instant.MIN).build(); + JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); + jwtValidator.setAllowEmptyExpiryClaim(false); + assertThat(jwtValidator.validate(jwt).hasErrors()).isTrue(); + } + + @Test + public void validateWhenNotAllowEmptyNotBeforeClaimAndNotBeforeIsNotSpecifiedThenReturnsSuccessfulResult() { + Jwt jwt = TestJwts.jwt().claims((c) -> c.remove(JwtClaimNames.NBF)).build(); + JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); + jwtValidator.setAllowEmptyNotBeforeClaim(false); + assertThat(jwtValidator.validate(jwt).hasErrors()).isTrue(); + } + @Test public void validateWhenExpiryIsValidAndNotBeforeIsNotSpecifiedThenReturnsSuccessfulResult() { Jwt jwt = TestJwts.jwt().build(); From ec05e65668022b3c9768451e9d5bb33332d1f010 Mon Sep 17 00:00:00 2001 From: Maximilian Klose Date: Wed, 14 May 2025 08:01:15 +0200 Subject: [PATCH 264/504] Add Equals and HashCode methods for better comparison. Closes gh-16394 Signed-off-by: Maximilian Klose --- .../endpoint/OAuth2AuthorizationRequest.java | 30 ++++++++++++++++++- .../OAuth2AuthorizationRequestTests.java | 23 ++++++++++++++ .../TestOAuth2AuthorizationRequests.java | 11 +++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequest.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequest.java index ff40a30785..37e323b5e4 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequest.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; @@ -188,6 +189,33 @@ public final class OAuth2AuthorizationRequest implements Serializable { return new Builder(AuthorizationGrantType.AUTHORIZATION_CODE); } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + OAuth2AuthorizationRequest that = (OAuth2AuthorizationRequest) obj; + + return Objects.equals(this.authorizationUri, that.authorizationUri) + && Objects.equals(this.authorizationGrantType, that.authorizationGrantType) + && Objects.equals(this.responseType, that.responseType) && Objects.equals(this.clientId, that.clientId) + && Objects.equals(this.redirectUri, that.redirectUri) && Objects.equals(this.scopes, that.scopes) + && Objects.equals(this.state, that.state) + && Objects.equals(this.additionalParameters, that.additionalParameters) + && Objects.equals(this.authorizationRequestUri, that.authorizationRequestUri) + && Objects.equals(this.attributes, that.attributes); + } + + @Override + public int hashCode() { + return Objects.hash(this.authorizationUri, this.clientId, this.authorizationGrantType, this.responseType, + this.redirectUri, this.scopes, this.state, this.additionalParameters, this.authorizationRequestUri, + this.attributes); + } + /** * Returns a new {@link Builder}, initialized with the values from the provided * {@code authorizationRequest}. diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequestTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequestTests.java index 1c4365560d..9d4b089f1e 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequestTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AuthorizationRequestTests.java @@ -365,4 +365,27 @@ public class OAuth2AuthorizationRequestTests { + "item1=null&item2=value2"); } + @Test + public void equalsWhenAllFieldsEqualEqualsThenTrue() { + OAuth2AuthorizationRequest authorizationRequest1 = TestOAuth2AuthorizationRequests.allFields().build(); + + OAuth2AuthorizationRequest authorizationRequest2 = TestOAuth2AuthorizationRequests.allFields().build(); + + assertThat(authorizationRequest1).isNotSameAs(authorizationRequest2); + assertThat(authorizationRequest1).isEqualTo(authorizationRequest2); + } + + @Test + public void hashCodeWhenAllFieldsEqualThenHashCodesAreEqual() { + OAuth2AuthorizationRequest authorizationRequest1 = TestOAuth2AuthorizationRequests.allFields().build(); + + OAuth2AuthorizationRequest authorizationRequest2 = TestOAuth2AuthorizationRequests.allFields().build(); + + int authorizationRequest1HashCode = authorizationRequest1.hashCode(); + int authorizationRequest2HashCode = authorizationRequest2.hashCode(); + + assertThat(authorizationRequest1).isNotSameAs(authorizationRequest2); + assertThat(authorizationRequest1HashCode).isEqualTo(authorizationRequest2HashCode); + } + } diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java index eaf559a28d..c95f0771b3 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/TestOAuth2AuthorizationRequests.java @@ -47,4 +47,15 @@ public final class TestOAuth2AuthorizationRequests { return request().scope("openid"); } + public static OAuth2AuthorizationRequest.Builder allFields() { + // @formatter:off + return request() + .authorizationRequestUri("https://example.com") + .additionalParameters(Map.of("someAdditionalParameterKey", "someAdditionalParameterValue")) + .parameters((parametersMap) -> + parametersMap.put("someParameterKey", "someParameterValue")) + .scope("someScope"); + // @formatter:on + } + } From 42790403da164175c43589b147c03fcc4afd3a0a Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 18 Apr 2025 17:37:48 +0800 Subject: [PATCH 265/504] Use SpringReactiveOpaqueTokenIntrospector Now that NimbusReactiveOpaqueTokenIntrospector is deprecated, this commit changes the Spring Security default to now use SpringReactiveOpaqueTokenIntrospector. Issue gh-15988 Signed-off-by: Yanming Zhou --- .../config/web/server/ServerHttpSecurity.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index a6d77b3683..a4063fced4 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -298,6 +298,7 @@ import org.springframework.web.util.pattern.PathPatternParser; * @author Parikshit Dutta * @author Ankur Pathak * @author Alexey Nesterov + * @author Yanming Zhou * @since 5.0 */ public class ServerHttpSecurity { @@ -5443,8 +5444,11 @@ public class ServerHttpSecurity { public OpaqueTokenSpec introspectionUri(String introspectionUri) { Assert.hasText(introspectionUri, "introspectionUri cannot be empty"); this.introspectionUri = introspectionUri; - this.introspector = () -> new SpringReactiveOpaqueTokenIntrospector(this.introspectionUri, - this.clientId, this.clientSecret); + this.introspector = () -> SpringReactiveOpaqueTokenIntrospector + .withIntrospectionUri(this.introspectionUri) + .clientId(this.clientId) + .clientSecret(this.clientSecret) + .build(); return this; } @@ -5459,8 +5463,11 @@ public class ServerHttpSecurity { Assert.notNull(clientSecret, "clientSecret cannot be null"); this.clientId = clientId; this.clientSecret = clientSecret; - this.introspector = () -> new SpringReactiveOpaqueTokenIntrospector(this.introspectionUri, - this.clientId, this.clientSecret); + this.introspector = () -> SpringReactiveOpaqueTokenIntrospector + .withIntrospectionUri(this.introspectionUri) + .clientId(this.clientId) + .clientSecret(this.clientSecret) + .build(); return this; } From da2d9aa8682138b4f436f9be4874447ee9e2acc9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 28 May 2025 14:01:46 -0600 Subject: [PATCH 266/504] Add Username Property to Exception Closes gh-17179 --- .../UsernameNotFoundException.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/core/src/main/java/org/springframework/security/core/userdetails/UsernameNotFoundException.java b/core/src/main/java/org/springframework/security/core/userdetails/UsernameNotFoundException.java index d1d969dc26..eff0e13adb 100644 --- a/core/src/main/java/org/springframework/security/core/userdetails/UsernameNotFoundException.java +++ b/core/src/main/java/org/springframework/security/core/userdetails/UsernameNotFoundException.java @@ -31,12 +31,15 @@ public class UsernameNotFoundException extends AuthenticationException { @Serial private static final long serialVersionUID = 1410688585992297006L; + private final String name; + /** * Constructs a UsernameNotFoundException with the specified message. * @param msg the detail message. */ public UsernameNotFoundException(String msg) { super(msg); + this.name = null; } /** @@ -47,6 +50,42 @@ public class UsernameNotFoundException extends AuthenticationException { */ public UsernameNotFoundException(String msg, Throwable cause) { super(msg, cause); + this.name = null; + } + + private UsernameNotFoundException(String msg, String name, Throwable cause) { + super(msg, cause); + this.name = name; + } + + /** + * Construct an exception based on a specific username + * @param username the invalid username + * @return the {@link UsernameNotFoundException} + * @since 7.0 + */ + public static UsernameNotFoundException fromUsername(String username) { + return fromUsername(username, null); + } + + /** + * Construct an exception based on a specific username + * @param username the invalid username + * @param cause any underlying cause + * @return the {@link UsernameNotFoundException} + * @since 7.0 + */ + public static UsernameNotFoundException fromUsername(String username, Throwable cause) { + return new UsernameNotFoundException("user not found", username, cause); + } + + /** + * Get the username that couldn't be found + * @return the username + * @since 7.0 + */ + public String getName() { + return this.name; } } From 215547f8c8ae1455a24b6cbc8f897bfc0c10ea4b Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 28 May 2025 14:13:02 -0600 Subject: [PATCH 267/504] Use UsernameNotFoundException Factory Issue gh-17179 --- .../security/provisioning/InMemoryUserDetailsManager.java | 2 +- .../ldap/authentication/PasswordComparisonAuthenticator.java | 2 +- .../ad/ActiveDirectoryLdapAuthenticationProvider.java | 3 +-- .../security/ldap/search/FilterBasedLdapUserSearch.java | 2 +- .../security/ldap/userdetails/LdapUserDetailsManager.java | 2 +- .../ReactivePreAuthenticatedAuthenticationManager.java | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java index 498e165342..0a17b16547 100644 --- a/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java @@ -164,7 +164,7 @@ public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetai public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails user = this.users.get(username.toLowerCase(Locale.ROOT)); if (user == null) { - throw new UsernameNotFoundException("user '" + username + "' not found"); + throw UsernameNotFoundException.fromUsername(username); } if (user instanceof CredentialsContainer) { return user; diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticator.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticator.java index 7d79d358ef..e158e87235 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticator.java +++ b/ldap/src/main/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticator.java @@ -93,7 +93,7 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic } } if (user == null) { - throw new UsernameNotFoundException("User not found: " + username); + throw UsernameNotFoundException.fromUsername(username); } if (logger.isTraceEnabled()) { logger.trace(LogMessage.format("Comparing password attribute '%s' for user '%s'", diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java index 6d43a67202..0ee5a54f0a 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java +++ b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java @@ -307,8 +307,7 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends AbstractLda throw ex; } // If we found no results, then the username/password did not match - UsernameNotFoundException userNameNotFoundException = new UsernameNotFoundException( - "User " + username + " not found in directory.", ex); + UsernameNotFoundException userNameNotFoundException = UsernameNotFoundException.fromUsername(username, ex); throw badCredentials(userNameNotFoundException); } } diff --git a/ldap/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java b/ldap/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java index 326b5c5fa1..2277b45463 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java +++ b/ldap/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java @@ -104,7 +104,7 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch { } catch (IncorrectResultSizeDataAccessException ex) { if (ex.getActualSize() == 0) { - throw new UsernameNotFoundException("User " + username + " not found in directory."); + throw UsernameNotFoundException.fromUsername(username); } // Search should never return multiple results if properly configured throw ex; diff --git a/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java b/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java index 53d46980ac..3d945a0805 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java +++ b/ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManager.java @@ -154,7 +154,7 @@ public class LdapUserDetailsManager implements UserDetailsManager { return new DirContextAdapter(attrs, LdapUtils.getFullDn(dn, ctx)); } catch (NameNotFoundException ex) { - throw new UsernameNotFoundException("User " + username + " not found", ex); + throw UsernameNotFoundException.fromUsername(username, ex); } }); } diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/ReactivePreAuthenticatedAuthenticationManager.java b/web/src/main/java/org/springframework/security/web/server/authentication/ReactivePreAuthenticatedAuthenticationManager.java index 83cc524283..2528157f60 100644 --- a/web/src/main/java/org/springframework/security/web/server/authentication/ReactivePreAuthenticatedAuthenticationManager.java +++ b/web/src/main/java/org/springframework/security/web/server/authentication/ReactivePreAuthenticatedAuthenticationManager.java @@ -62,7 +62,7 @@ public class ReactivePreAuthenticatedAuthenticationManager implements ReactiveAu .filter(this::supports) .map(Authentication::getName) .flatMap(this.userDetailsService::findByUsername) - .switchIfEmpty(Mono.error(() -> new UsernameNotFoundException("User not found"))) + .switchIfEmpty(Mono.error(() -> UsernameNotFoundException.fromUsername(authentication.getName()))) .doOnNext(this.userDetailsChecker::check) .map((userDetails) -> { PreAuthenticatedAuthenticationToken result = new PreAuthenticatedAuthenticationToken(userDetails, From 37a814bc29ff97026220a7c4e697639480374d65 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 28 May 2025 15:48:17 -0600 Subject: [PATCH 268/504] Add 7.0 -> 8.0 Migration Guide Closes gh-17182 --- docs/modules/ROOT/nav.adoc | 13 +- .../pages/migration-7/authentication.adoc | 68 --- .../ROOT/pages/migration-7/authorization.adoc | 24 - .../ROOT/pages/migration-7/configuration.adoc | 125 ----- docs/modules/ROOT/pages/migration-7/ldap.adoc | 11 - .../ROOT/pages/migration-7/oauth2.adoc | 172 ------ .../modules/ROOT/pages/migration-7/saml2.adoc | 165 ------ docs/modules/ROOT/pages/migration-7/web.adoc | 523 ------------------ .../{migration-7 => migration-8}/index.adoc | 8 +- docs/modules/ROOT/pages/migration/index.adoc | 32 +- .../ROOT/pages/migration/reactive.adoc | 97 ---- .../migration/servlet/authentication.adoc | 187 ------- .../migration/servlet/authorization.adoc | 136 ----- .../pages/migration/servlet/exploits.adoc | 44 -- .../ROOT/pages/migration/servlet/oauth2.adoc | 80 +++ .../migration/servlet/session-management.adoc | 49 -- 16 files changed, 98 insertions(+), 1636 deletions(-) delete mode 100644 docs/modules/ROOT/pages/migration-7/authentication.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/authorization.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/configuration.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/ldap.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/oauth2.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/saml2.adoc delete mode 100644 docs/modules/ROOT/pages/migration-7/web.adoc rename docs/modules/ROOT/pages/{migration-7 => migration-8}/index.adoc (52%) delete mode 100644 docs/modules/ROOT/pages/migration/servlet/authentication.adoc delete mode 100644 docs/modules/ROOT/pages/migration/servlet/authorization.adoc delete mode 100644 docs/modules/ROOT/pages/migration/servlet/exploits.adoc create mode 100644 docs/modules/ROOT/pages/migration/servlet/oauth2.adoc delete mode 100644 docs/modules/ROOT/pages/migration/servlet/session-management.adoc 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[] From 6d3b54df21ec0cffc30c8b3e0784220bd117a87d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 27 May 2025 13:13:54 -0600 Subject: [PATCH 269/504] Change Type Validation Default NimbusJwtDecoder and NimbusReactiveJwtDecoder now use Spring Security's JwtTypeValidator by default instead of Nimbus's type validator. Closes gh-17181 --- ...ckChannelLogoutAuthenticationProvider.java | 16 ++-- ...elLogoutReactiveAuthenticationManager.java | 15 ++-- .../ROOT/pages/migration/reactive.adoc | 79 +++++++++++++++++++ .../security/oauth2/jwt/JwtValidators.java | 8 +- .../security/oauth2/jwt/NimbusJwtDecoder.java | 6 +- .../oauth2/jwt/NimbusReactiveJwtDecoder.java | 8 +- .../oauth2/jwt/JwtValidatorsTests.java | 3 +- .../oauth2/jwt/NimbusJwtDecoderTests.java | 10 +-- .../jwt/NimbusReactiveJwtDecoderTests.java | 3 + 9 files changed, 111 insertions(+), 37 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutAuthenticationProvider.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutAuthenticationProvider.java index 07debd7420..3209736f51 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutAuthenticationProvider.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcBackChannelLogoutAuthenticationProvider.java @@ -18,11 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.cl import java.util.function.Function; -import com.nimbusds.jose.JOSEObjectType; -import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier; -import com.nimbusds.jose.proc.JOSEObjectTypeVerifier; -import com.nimbusds.jose.proc.SecurityContext; - import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; @@ -38,6 +33,7 @@ import org.springframework.security.oauth2.jwt.BadJwtException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtDecoderFactory; +import org.springframework.security.oauth2.jwt.JwtTypeValidator; import org.springframework.security.oauth2.jwt.JwtValidators; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.util.Assert; @@ -67,8 +63,10 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio * Construct an {@link OidcBackChannelLogoutAuthenticationProvider} */ OidcBackChannelLogoutAuthenticationProvider() { + JwtTypeValidator type = new JwtTypeValidator("JWT", "logout+jwt"); + type.setAllowEmpty(true); Function> jwtValidator = (clientRegistration) -> JwtValidators - .createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration)); + .createDefaultWithValidators(type, new OidcBackChannelLogoutTokenValidator(clientRegistration)); this.logoutTokenDecoderFactory = (clientRegistration) -> { String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri(); if (!StringUtils.hasText(jwkSetUri)) { @@ -79,11 +77,7 @@ final class OidcBackChannelLogoutAuthenticationProvider implements Authenticatio null); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); } - JOSEObjectTypeVerifier typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null, - JOSEObjectType.JWT, new JOSEObjectType("logout+jwt")); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri) - .jwtProcessorCustomizer((processor) -> processor.setJWSTypeVerifier(typeVerifier)) - .build(); + NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build(); decoder.setJwtValidator(jwtValidator.apply(clientRegistration)); decoder.setClaimSetConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverter()); return decoder; diff --git a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java index 04334be1bf..155d80f01a 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java +++ b/config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java @@ -18,10 +18,6 @@ package org.springframework.security.config.web.server; import java.util.function.Function; -import com.nimbusds.jose.JOSEObjectType; -import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier; -import com.nimbusds.jose.proc.JOSEObjectTypeVerifier; -import com.nimbusds.jose.proc.JWKSecurityContext; import reactor.core.publisher.Mono; import org.springframework.security.authentication.AuthenticationProvider; @@ -41,6 +37,7 @@ import org.springframework.security.oauth2.jwt.BadJwtException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtDecoderFactory; +import org.springframework.security.oauth2.jwt.JwtTypeValidator; import org.springframework.security.oauth2.jwt.JwtValidators; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; @@ -72,8 +69,10 @@ final class OidcBackChannelLogoutReactiveAuthenticationManager implements Reacti * Construct an {@link OidcBackChannelLogoutReactiveAuthenticationManager} */ OidcBackChannelLogoutReactiveAuthenticationManager() { + JwtTypeValidator type = new JwtTypeValidator("JWT", "logout+jwt"); + type.setAllowEmpty(true); Function> jwtValidator = (clientRegistration) -> JwtValidators - .createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration)); + .createDefaultWithValidators(type, new OidcBackChannelLogoutTokenValidator(clientRegistration)); this.logoutTokenDecoderFactory = (clientRegistration) -> { String jwkSetUri = clientRegistration.getProviderDetails().getJwkSetUri(); if (!StringUtils.hasText(jwkSetUri)) { @@ -84,11 +83,7 @@ final class OidcBackChannelLogoutReactiveAuthenticationManager implements Reacti null); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); } - JOSEObjectTypeVerifier typeVerifier = new DefaultJOSEObjectTypeVerifier<>(null, - JOSEObjectType.JWT, new JOSEObjectType("logout+jwt")); - NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri) - .jwtProcessorCustomizer((processor) -> processor.setJWSTypeVerifier(typeVerifier)) - .build(); + NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build(); decoder.setJwtValidator(jwtValidator.apply(clientRegistration)); decoder.setClaimSetConverter( new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters())); diff --git a/docs/modules/ROOT/pages/migration/reactive.adoc b/docs/modules/ROOT/pages/migration/reactive.adoc index 17d33ff586..44caa91592 100644 --- a/docs/modules/ROOT/pages/migration/reactive.adoc +++ b/docs/modules/ROOT/pages/migration/reactive.adoc @@ -1,3 +1,82 @@ = 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. + +== 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() { + NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.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 = NimbusReactiveJwtDecoder.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 +NimbusReactiveJwtDecoder jwtDecoder() { + NimbusJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withIssuerLocation(location) + // ... your remaining configuration <1> + .build(); + jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(location)); <2> + return jwtDecoder; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun jwtDecoder(): NimbusReactiveJwtDecoder { + val jwtDecoder = NimbusReactiveJwtDecoder.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/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java index b958328c8d..a904684398 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java @@ -75,8 +75,8 @@ public final class JwtValidators { * supplied */ public static OAuth2TokenValidator createDefault() { - return new DelegatingOAuth2TokenValidator<>( - Arrays.asList(new JwtTimestampValidator(), new X509CertificateThumbprintValidator( + return new DelegatingOAuth2TokenValidator<>(Arrays.asList(JwtTypeValidator.jwt(), new JwtTimestampValidator(), + new X509CertificateThumbprintValidator( X509CertificateThumbprintValidator.DEFAULT_X509_CERTIFICATE_SUPPLIER))); } @@ -104,6 +104,10 @@ public final class JwtValidators { if (jwtTimestampValidator == null) { tokenValidators.add(0, new JwtTimestampValidator()); } + JwtTypeValidator typeValidator = CollectionUtils.findValueOfType(tokenValidators, JwtTypeValidator.class); + if (typeValidator == null) { + tokenValidators.add(0, JwtTypeValidator.jwt()); + } return new DelegatingOAuth2TokenValidator<>(tokenValidators); } diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java index eb5efbabec..66f0b70e45 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java @@ -279,7 +279,7 @@ public final class NimbusJwtDecoder implements JwtDecoder { private Function, Set> defaultAlgorithms = (source) -> Set .of(JWSAlgorithm.RS256); - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private final Set signatureAlgorithms = new HashSet<>(); @@ -548,7 +548,7 @@ public final class NimbusJwtDecoder implements JwtDecoder { private JWSAlgorithm jwsAlgorithm; - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private final RSAPublicKey key; @@ -680,7 +680,7 @@ public final class NimbusJwtDecoder implements JwtDecoder { private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256; - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private Consumer> jwtProcessorCustomizer; diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java index 32f97c1355..c76532689d 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java @@ -324,7 +324,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { private Function>> defaultAlgorithms = (source) -> Mono .just(Set.of(JWSAlgorithm.RS256)); - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private Set signatureAlgorithms = new HashSet<>(); @@ -547,7 +547,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { private JWSAlgorithm jwsAlgorithm; - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private Consumer> jwtProcessorCustomizer; @@ -682,7 +682,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256; - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private Consumer> jwtProcessorCustomizer; @@ -814,7 +814,7 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.RS256; - private JOSEObjectTypeVerifier typeVerifier = JWT_TYPE_VERIFIER; + private JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; private Consumer> jwtProcessorCustomizer; diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java index 33174e9181..dad08edb69 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtValidatorsTests.java @@ -62,7 +62,8 @@ public class JwtValidatorsTests { assertThat(containsByType(validator, JwtTimestampValidator.class)).isTrue(); assertThat(containsByType(validator, X509CertificateThumbprintValidator.class)).isTrue(); - assertThat(Objects.requireNonNull(tokenValidators).size()).isEqualTo(2); + assertThat(containsByType(validator, JwtTypeValidator.class)).isTrue(); + assertThat(Objects.requireNonNull(tokenValidators).size()).isEqualTo(3); } @Test diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java index 9b7805a0d8..91db639c45 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java @@ -458,10 +458,8 @@ public class NimbusJwtDecoderTests { // @formatter:off NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(publicKey) .signatureAlgorithm(SignatureAlgorithm.RS256) - .jwtProcessorCustomizer((p) -> p - .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) - ) .build(); + decoder.setJwtValidator(JwtValidators.createDefaultWithValidators(new JwtTypeValidator("JWS"))); // @formatter:on assertThat(decoder.decode(signedJwt.serialize()).hasClaim(JwtClaimNames.EXP)).isNotNull(); } @@ -575,10 +573,8 @@ public class NimbusJwtDecoderTests { // @formatter:off NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey) .macAlgorithm(MacAlgorithm.HS256) - .jwtProcessorCustomizer((p) -> p - .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) - ) .build(); + decoder.setJwtValidator(JwtValidators.createDefaultWithValidators(new JwtTypeValidator("JWS"))); // @formatter:on assertThat(decoder.decode(signedJwt.serialize()).hasClaim(JwtClaimNames.EXP)).isNotNull(); } @@ -837,6 +833,7 @@ public class NimbusJwtDecoderTests { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(TestKeys.DEFAULT_PUBLIC_KEY) .validateType(false) .build(); + jwtDecoder.setJwtValidator((jwt) -> OAuth2TokenValidatorResult.success()); RSAPrivateKey privateKey = TestKeys.DEFAULT_PRIVATE_KEY; SignedJWT jwt = signedJwt(privateKey, new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JOSE).build(), @@ -849,6 +846,7 @@ public class NimbusJwtDecoderTests { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(TestKeys.DEFAULT_SECRET_KEY) .validateType(false) .build(); + jwtDecoder.setJwtValidator((jwt) -> OAuth2TokenValidatorResult.success()); SignedJWT jwt = signedJwt(TestKeys.DEFAULT_SECRET_KEY, new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JOSE).build(), new JWTClaimsSet.Builder().subject("subject").build()); diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java index 6ec57ab2cc..bee51921a6 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java @@ -667,6 +667,7 @@ public class NimbusReactiveJwtDecoderTests { NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withPublicKey(TestKeys.DEFAULT_PUBLIC_KEY) .validateType(false) .build(); + jwtDecoder.setJwtValidator((jwt) -> OAuth2TokenValidatorResult.success()); RSAPrivateKey privateKey = TestKeys.DEFAULT_PRIVATE_KEY; SignedJWT jwt = signedJwt(privateKey, new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JOSE).build(), @@ -679,6 +680,7 @@ public class NimbusReactiveJwtDecoderTests { NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withSecretKey(TestKeys.DEFAULT_SECRET_KEY) .validateType(false) .build(); + jwtDecoder.setJwtValidator((jwt) -> OAuth2TokenValidatorResult.success()); SignedJWT jwt = signedJwt(TestKeys.DEFAULT_SECRET_KEY, new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JOSE).build(), new JWTClaimsSet.Builder().subject("subject").build()); @@ -693,6 +695,7 @@ public class NimbusReactiveJwtDecoderTests { NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withJwkSource((jwt) -> Flux.just(jwk)) .validateType(false) .build(); + jwtDecoder.setJwtValidator((jwt) -> OAuth2TokenValidatorResult.success()); SignedJWT jwt = signedJwt(TestKeys.DEFAULT_PRIVATE_KEY, new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JOSE).build(), new JWTClaimsSet.Builder().subject("subject").build()); From 9a3d076bfdfa3a2031dfd089601faae0c227bc76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 03:39:38 +0000 Subject: [PATCH 270/504] Bump org.hibernate.orm:hibernate-core from 6.6.15.Final to 6.6.17.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.15.Final to 6.6.17.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.17/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.17) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.17.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ca108e9b2..808c1ecbb1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.15.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From fed198f3f0325b216128605319194b6620058099 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 03:56:04 +0000 Subject: [PATCH 271/504] Bump org.hibernate.orm:hibernate-core from 6.6.15.Final to 6.6.17.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.15.Final to 6.6.17.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.17/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.17) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.17.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04b1cfa6b1..76b2039e00 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.15.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From fd4f06a66e06d4dc586c7f6ba06499eb65879e7e Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Thu, 17 Apr 2025 19:25:15 +0300 Subject: [PATCH 272/504] Support Spring Data container types for AuthorizeReturnObject Closes gh-15994 Signed-off-by: Evgeniy Cheban --- .../AuthorizationProxyDataConfiguration.java | 52 +++++++- ...ePostMethodSecurityConfigurationTests.java | 112 ++++++++++++++++-- 2 files changed, 152 insertions(+), 12 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyDataConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyDataConfiguration.java index e446ee2736..092bb83a8d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyDataConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyDataConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,22 @@ package org.springframework.security.config.annotation.method.configuration; +import java.util.List; + import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import org.springframework.core.Ordered; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.geo.GeoPage; +import org.springframework.data.geo.GeoResult; +import org.springframework.data.geo.GeoResults; import org.springframework.security.aot.hint.SecurityHintsRegistrar; import org.springframework.security.authorization.AuthorizationProxyFactory; +import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; import org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar; @Configuration(proxyBeanMethods = false) @@ -34,4 +43,45 @@ final class AuthorizationProxyDataConfiguration implements AopInfrastructureBean return new AuthorizeReturnObjectDataHintsRegistrar(proxyFactory); } + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + DataTargetVisitor dataTargetVisitor() { + return new DataTargetVisitor(); + } + + private static final class DataTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered { + + private static final int DEFAULT_ORDER = 200; + + @Override + public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { + if (target instanceof GeoResults geoResults) { + return new GeoResults<>(proxyFactory.proxy(geoResults.getContent()), geoResults.getAverageDistance()); + } + if (target instanceof GeoResult geoResult) { + return new GeoResult<>(proxyFactory.proxy(geoResult.getContent()), geoResult.getDistance()); + } + if (target instanceof GeoPage geoPage) { + GeoResults results = new GeoResults<>(proxyFactory.proxy(geoPage.getContent()), + geoPage.getAverageDistance()); + return new GeoPage<>(results, geoPage.getPageable(), geoPage.getTotalElements()); + } + if (target instanceof PageImpl page) { + List content = proxyFactory.proxy(page.getContent()); + return new PageImpl<>(content, page.getPageable(), page.getTotalElements()); + } + if (target instanceof SliceImpl slice) { + List content = proxyFactory.proxy(slice.getContent()); + return new SliceImpl<>(content, slice.getPageable(), slice.hasNext()); + } + return null; + } + + @Override + public int getOrder() { + return DEFAULT_ORDER; + } + + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index fe9ccfc77e..b8e46ffea0 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -63,7 +63,14 @@ import org.springframework.context.annotation.Role; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationConfigurationException; -import org.springframework.core.annotation.Order; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.geo.Distance; +import org.springframework.data.geo.GeoPage; +import org.springframework.data.geo.GeoResult; +import org.springframework.data.geo.GeoResults; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; @@ -756,6 +763,28 @@ public class PrePostMethodSecurityConfigurationTests { assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude); } + @Test + @WithMockUser(authorities = "airplane:read") + public void findGeoResultByIdWhenAuthorizedResultThenAuthorizes() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + GeoResult geoResultFlight = flights.findGeoResultFlightById("1"); + Flight flight = geoResultFlight.getContent(); + assertThatNoException().isThrownBy(flight::getAltitude); + assertThatNoException().isThrownBy(flight::getSeats); + } + + @Test + @WithMockUser(authorities = "seating:read") + public void findGeoResultByIdWhenUnauthorizedResultThenDenies() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + GeoResult geoResultFlight = flights.findGeoResultFlightById("1"); + Flight flight = geoResultFlight.getContent(); + assertThatNoException().isThrownBy(flight::getSeats); + assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(flight::getAltitude); + } + @Test @WithMockUser(authorities = "airplane:read") public void findByIdWhenAuthorizedResponseEntityThenAuthorizes() { @@ -827,6 +856,46 @@ public class PrePostMethodSecurityConfigurationTests { .doesNotContain("Kevin Mitnick")); } + @Test + @WithMockUser(authorities = "airplane:read") + public void findPageWhenPostFilterThenFilters() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + flights.findPage() + .forEach((flight) -> assertThat(flight.getPassengers()).extracting(Passenger::getName) + .doesNotContain("Kevin Mitnick")); + } + + @Test + @WithMockUser(authorities = "airplane:read") + public void findSliceWhenPostFilterThenFilters() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + flights.findSlice() + .forEach((flight) -> assertThat(flight.getPassengers()).extracting(Passenger::getName) + .doesNotContain("Kevin Mitnick")); + } + + @Test + @WithMockUser(authorities = "airplane:read") + public void findGeoPageWhenPostFilterThenFilters() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + flights.findGeoPage() + .forEach((flight) -> assertThat(flight.getContent().getPassengers()).extracting(Passenger::getName) + .doesNotContain("Kevin Mitnick")); + } + + @Test + @WithMockUser(authorities = "airplane:read") + public void findGeoResultsWhenPostFilterThenFilters() { + this.spring.register(AuthorizeResultConfig.class).autowire(); + FlightRepository flights = this.spring.getContext().getBean(FlightRepository.class); + flights.findGeoResults() + .forEach((flight) -> assertThat(flight.getContent().getPassengers()).extracting(Passenger::getName) + .doesNotContain("Kevin Mitnick")); + } + @Test @WithMockUser(authorities = "airplane:read") public void findAllWhenPreFilterThenFilters() { @@ -1762,16 +1831,8 @@ public class PrePostMethodSecurityConfigurationTests { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - @Order(1) - static TargetVisitor mock() { - return Mockito.mock(TargetVisitor.class); - } - - @Bean - @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - @Order(0) - static TargetVisitor skipValueTypes() { - return TargetVisitor.defaultsSkipValueTypes(); + static TargetVisitor customTargetVisitor() { + return TargetVisitor.of(Mockito.mock(), TargetVisitor.defaultsSkipValueTypes()); } @Bean @@ -1802,10 +1863,39 @@ public class PrePostMethodSecurityConfigurationTests { return this.flights.values().iterator(); } + Page findPage() { + return new PageImpl<>(new ArrayList<>(this.flights.values())); + } + + Slice findSlice() { + return new SliceImpl<>(new ArrayList<>(this.flights.values())); + } + + GeoPage findGeoPage() { + List> results = new ArrayList<>(); + for (Flight flight : this.flights.values()) { + results.add(new GeoResult<>(flight, new Distance(flight.altitude))); + } + return new GeoPage<>(new GeoResults<>(results)); + } + + GeoResults findGeoResults() { + List> results = new ArrayList<>(); + for (Flight flight : this.flights.values()) { + results.add(new GeoResult<>(flight, new Distance(flight.altitude))); + } + return new GeoResults<>(results); + } + Flight findById(String id) { return this.flights.get(id); } + GeoResult findGeoResultFlightById(String id) { + Flight flight = this.flights.get(id); + return new GeoResult<>(flight, new Distance(flight.altitude)); + } + Flight save(Flight flight) { this.flights.put(flight.getId(), flight); return flight; From 5517d8fe3a2b4d2ea85e1e06b42e55caaadb04a8 Mon Sep 17 00:00:00 2001 From: Pat McCusker Date: Fri, 16 May 2025 18:33:36 -0400 Subject: [PATCH 273/504] Deprecate the X5T JOSE Header name Closes gh-16979 Signed-off-by: Pat McCusker --- .../security/oauth2/jwt/JoseHeader.java | 18 +++++++++++++++++- .../security/oauth2/jwt/JoseHeaderNames.java | 10 +++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java index 3b749fe395..38c41f29bd 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,7 +119,15 @@ class JoseHeader { * thumbprint (a.k.a. digest) of the DER encoding of the X.509 certificate * corresponding to the key used to digitally sign the JWS or encrypt the JWE. * @return the X.509 certificate SHA-1 thumbprint + * @deprecated The SHA-1 algorithm has been proven to be vulnerable to collision + * attacks and should not be used. See the
Google + * Security Blog for more info. + * @see Announcing + * the first SHA1 collision */ + @Deprecated public String getX509SHA1Thumbprint() { return getHeader(JoseHeaderNames.X5T); } @@ -271,7 +279,15 @@ class JoseHeader { * corresponding to the key used to digitally sign the JWS or encrypt the JWE. * @param x509SHA1Thumbprint the X.509 certificate SHA-1 thumbprint * @return the {@link AbstractBuilder} + * @deprecated The SHA-1 algorithm has been proven to be vulnerable to collision + * attacks and should not be used. See the Google + * Security Blog for more info. + * @see Announcing + * the first SHA1 collision */ + @Deprecated public B x509SHA1Thumbprint(String x509SHA1Thumbprint) { return header(JoseHeaderNames.X5T, x509SHA1Thumbprint); } diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java index a53318584f..b20863d6d5 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,7 +76,15 @@ public final class JoseHeaderNames { * {@code x5t} - the X.509 certificate SHA-1 thumbprint header is a base64url-encoded * SHA-1 thumbprint (a.k.a. digest) of the DER encoding of the X.509 certificate * corresponding to the key used to digitally sign a JWS or encrypt a JWE + * @deprecated The SHA-1 algorithm has been proven to be vulnerable to collision + * attacks and should not be used. See the Google + * Security Blog for more info. + * @see Announcing + * the first SHA1 collision */ + @Deprecated public static final String X5T = "x5t"; /** From 72771c28c329099431414f5504df9c13631f05b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 03:27:50 +0000 Subject: [PATCH 274/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.29.2.RELEASE to 0.29.3.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.29.2.RELEASE...0.29.3.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-version: 0.29.3.RELEASE dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04b1cfa6b1..17bd57d66b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.2.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.3.RELEASE' [plugins] From 227a2cc0c72b06f718fd62b6d1a54a60c613dc9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 03:51:03 +0000 Subject: [PATCH 275/504] Bump com.webauthn4j:webauthn4j-core Bumps [com.webauthn4j:webauthn4j-core](https://github.com/webauthn4j/webauthn4j) from 0.29.2.RELEASE to 0.29.3.RELEASE. - [Release notes](https://github.com/webauthn4j/webauthn4j/releases) - [Changelog](https://github.com/webauthn4j/webauthn4j/blob/master/github-release-notes-generator.yml) - [Commits](https://github.com/webauthn4j/webauthn4j/compare/0.29.2.RELEASE...0.29.3.RELEASE) --- updated-dependencies: - dependency-name: com.webauthn4j:webauthn4j-core dependency-version: 0.29.3.RELEASE dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6a16532177..efc1c81dbe 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -108,7 +108,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1" -webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.2.RELEASE' +webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.29.3.RELEASE' [plugins] From ada75e76a6a9c435a842916bf1e8061c43215b67 Mon Sep 17 00:00:00 2001 From: Mark Bonnekessel <2949525+marbon87@users.noreply.github.com> Date: Fri, 16 May 2025 15:49:00 +0200 Subject: [PATCH 276/504] Add builder to create NimbusJwtDecoder with JwkSource Signed-off-by: Mark Bonnekessel <2949525+marbon87@users.noreply.github.com> --- .../security/oauth2/jwt/NimbusJwtDecoder.java | 112 ++++++++++++++++++ .../oauth2/jwt/NimbusJwtDecoderTests.java | 10 ++ 2 files changed, 122 insertions(+) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java index 66f0b70e45..d762e919ac 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java @@ -261,6 +261,16 @@ public final class NimbusJwtDecoder implements JwtDecoder { return new SecretKeyJwtDecoderBuilder(secretKey); } + /** + * Use the given {@code JWKSource} to create a JwkSourceJwtDecoderBuilder. + * @param jwkSource the JWK Source to use + * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations + * @since 7.0 + */ + public static JwkSourceJwtDecoderBuilder withJwkSource(JWKSource jwkSource) { + return new JwkSourceJwtDecoderBuilder(jwkSource); + } + /** * A builder for creating {@link NimbusJwtDecoder} instances based on a * JWK Set @@ -535,6 +545,108 @@ public final class NimbusJwtDecoder implements JwtDecoder { } + /** + * A builder for creating {@link NimbusJwtDecoder} instances based on a + * {@code JWKSource}. + */ + public static final class JwkSourceJwtDecoderBuilder { + + private static final JOSEObjectTypeVerifier NO_TYPE_VERIFIER = (header, context) -> { + }; + + private final Function, Set> defaultAlgorithms = (source) -> Set + .of(JWSAlgorithm.RS256); + + private final JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; + + private final Set signatureAlgorithms = new HashSet<>(); + + private Consumer> jwtProcessorCustomizer; + + private final JWKSource jwkSource; + + private JwkSourceJwtDecoderBuilder(JWKSource jwkSource) { + Assert.notNull(jwkSource, "jwkSource cannot be null"); + this.jwkSource = jwkSource; + this.jwtProcessorCustomizer = (processor) -> { + }; + } + + /** + * Append the given signing + * algorithm to the set of algorithms to use. + * @param signatureAlgorithm the algorithm to use + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + */ + public JwkSourceJwtDecoderBuilder jwsAlgorithm(SignatureAlgorithm signatureAlgorithm) { + Assert.notNull(signatureAlgorithm, "signatureAlgorithm cannot be null"); + this.signatureAlgorithms.add(signatureAlgorithm); + return this; + } + + /** + * Configure the list of + * algorithms to use with the given {@link Consumer}. + * @param signatureAlgorithmsConsumer a {@link Consumer} for further configuring + * the algorithm list + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + */ + public JwkSourceJwtDecoderBuilder jwsAlgorithms(Consumer> signatureAlgorithmsConsumer) { + Assert.notNull(signatureAlgorithmsConsumer, "signatureAlgorithmsConsumer cannot be null"); + signatureAlgorithmsConsumer.accept(this.signatureAlgorithms); + return this; + } + + /** + * Use the given {@link Consumer} to customize the {@link JWTProcessor + * ConfigurableJWTProcessor} before passing it to the build + * {@link NimbusJwtDecoder}. + * @param jwtProcessorCustomizer the callback used to alter the processor + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + * @since 5.4 + */ + public JwkSourceJwtDecoderBuilder jwtProcessorCustomizer( + Consumer> jwtProcessorCustomizer) { + Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null"); + this.jwtProcessorCustomizer = jwtProcessorCustomizer; + return this; + } + + JWSKeySelector jwsKeySelector(JWKSource jwkSource) { + if (this.signatureAlgorithms.isEmpty()) { + return new JWSVerificationKeySelector<>(this.defaultAlgorithms.apply(jwkSource), jwkSource); + } + Set jwsAlgorithms = new HashSet<>(); + for (SignatureAlgorithm signatureAlgorithm : this.signatureAlgorithms) { + JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName()); + jwsAlgorithms.add(jwsAlgorithm); + } + return new JWSVerificationKeySelector<>(jwsAlgorithms, jwkSource); + } + + JWTProcessor processor() { + ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor<>(); + jwtProcessor.setJWSTypeVerifier(this.typeVerifier); + jwtProcessor.setJWSKeySelector(jwsKeySelector(this.jwkSource)); + // Spring Security validates the claim set independent from Nimbus + jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { + }); + this.jwtProcessorCustomizer.accept(jwtProcessor); + return jwtProcessor; + } + + /** + * Build the configured {@link NimbusJwtDecoder}. + * @return the configured {@link NimbusJwtDecoder} + */ + public NimbusJwtDecoder build() { + return new NimbusJwtDecoder(processor()); + } + + } + /** * A builder for creating {@link NimbusJwtDecoder} instances based on a public key. */ diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java index 91db639c45..7dd353d8f1 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java @@ -42,6 +42,7 @@ import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSSigner; import com.nimbusds.jose.crypto.MACSigner; import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.BadJOSEException; import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier; @@ -557,6 +558,15 @@ public class NimbusJwtDecoderTests { // @formatter:on } + @Test + public void withJwkSourceWhenDefaultsThenUsesProvidedJwkSource() throws Exception { + JWKSource source = mock(JWKSource.class); + given(source.get(any(), any())).willReturn(JWKSet.parse(JWK_SET).getKeys()); + NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSource(source).build(); + Jwt jwt = decoder.decode(SIGNED_JWT); + assertThat(jwt.getClaimAsString("sub")).isEqualTo("test-subject"); + } + // gh-8730 @Test public void withSecretKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception { From 195f9334382855e3af12aee6f7519dcf4cb725ef Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 28 May 2025 17:42:28 -0600 Subject: [PATCH 277/504] Allow Default Ordering for TargetVisitor In tests, we want to both test that functionality works and also demonstrate common or expected usage, where possible. It is likely incorrect to use @Order(0) for a target visitor as this states that it should take precedence over all Spring Security visitors defined at a lower precedence. Also, it appears this may have been added this way because of a mock visitor that appears to be unused by any tests. Further, when an application has multiple visitors, they should use the TargetVisitor.of method to publish one bean with the order determined by the order of the method parameters instead of having two separate beans. This commit removes the @Order(0) annotation and also the mock visitor, deferring to the natural ordering afforded by the framework. Issue gh-15994 --- .../PrePostMethodSecurityConfigurationTests.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index b8e46ffea0..404750ee95 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -40,7 +40,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mockito; import org.springframework.aop.Advisor; import org.springframework.aop.Pointcut; @@ -1831,8 +1830,8 @@ public class PrePostMethodSecurityConfigurationTests { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - static TargetVisitor customTargetVisitor() { - return TargetVisitor.of(Mockito.mock(), TargetVisitor.defaultsSkipValueTypes()); + static TargetVisitor skipValueTypes() { + return TargetVisitor.defaultsSkipValueTypes(); } @Bean From d52e0b6a051d817c9af0c4ab8bc714b3233a9842 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 2 Jun 2025 15:53:27 -0600 Subject: [PATCH 278/504] Polish NimbusJwtDecoder - Aligned JwkSourceJwtDecoderBuilder's relative position with its corresponding static factory - Added @since to JwkSourceJwtDecoderBuilder PR gh-17046 --- .../security/oauth2/jwt/NimbusJwtDecoder.java | 206 +++++++++--------- 1 file changed, 104 insertions(+), 102 deletions(-) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java index d762e919ac..776f4e7335 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java @@ -545,108 +545,6 @@ public final class NimbusJwtDecoder implements JwtDecoder { } - /** - * A builder for creating {@link NimbusJwtDecoder} instances based on a - * {@code JWKSource}. - */ - public static final class JwkSourceJwtDecoderBuilder { - - private static final JOSEObjectTypeVerifier NO_TYPE_VERIFIER = (header, context) -> { - }; - - private final Function, Set> defaultAlgorithms = (source) -> Set - .of(JWSAlgorithm.RS256); - - private final JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; - - private final Set signatureAlgorithms = new HashSet<>(); - - private Consumer> jwtProcessorCustomizer; - - private final JWKSource jwkSource; - - private JwkSourceJwtDecoderBuilder(JWKSource jwkSource) { - Assert.notNull(jwkSource, "jwkSource cannot be null"); - this.jwkSource = jwkSource; - this.jwtProcessorCustomizer = (processor) -> { - }; - } - - /** - * Append the given signing - * algorithm to the set of algorithms to use. - * @param signatureAlgorithm the algorithm to use - * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations - */ - public JwkSourceJwtDecoderBuilder jwsAlgorithm(SignatureAlgorithm signatureAlgorithm) { - Assert.notNull(signatureAlgorithm, "signatureAlgorithm cannot be null"); - this.signatureAlgorithms.add(signatureAlgorithm); - return this; - } - - /** - * Configure the list of - * algorithms to use with the given {@link Consumer}. - * @param signatureAlgorithmsConsumer a {@link Consumer} for further configuring - * the algorithm list - * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations - */ - public JwkSourceJwtDecoderBuilder jwsAlgorithms(Consumer> signatureAlgorithmsConsumer) { - Assert.notNull(signatureAlgorithmsConsumer, "signatureAlgorithmsConsumer cannot be null"); - signatureAlgorithmsConsumer.accept(this.signatureAlgorithms); - return this; - } - - /** - * Use the given {@link Consumer} to customize the {@link JWTProcessor - * ConfigurableJWTProcessor} before passing it to the build - * {@link NimbusJwtDecoder}. - * @param jwtProcessorCustomizer the callback used to alter the processor - * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations - * @since 5.4 - */ - public JwkSourceJwtDecoderBuilder jwtProcessorCustomizer( - Consumer> jwtProcessorCustomizer) { - Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null"); - this.jwtProcessorCustomizer = jwtProcessorCustomizer; - return this; - } - - JWSKeySelector jwsKeySelector(JWKSource jwkSource) { - if (this.signatureAlgorithms.isEmpty()) { - return new JWSVerificationKeySelector<>(this.defaultAlgorithms.apply(jwkSource), jwkSource); - } - Set jwsAlgorithms = new HashSet<>(); - for (SignatureAlgorithm signatureAlgorithm : this.signatureAlgorithms) { - JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName()); - jwsAlgorithms.add(jwsAlgorithm); - } - return new JWSVerificationKeySelector<>(jwsAlgorithms, jwkSource); - } - - JWTProcessor processor() { - ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor<>(); - jwtProcessor.setJWSTypeVerifier(this.typeVerifier); - jwtProcessor.setJWSKeySelector(jwsKeySelector(this.jwkSource)); - // Spring Security validates the claim set independent from Nimbus - jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { - }); - this.jwtProcessorCustomizer.accept(jwtProcessor); - return jwtProcessor; - } - - /** - * Build the configured {@link NimbusJwtDecoder}. - * @return the configured {@link NimbusJwtDecoder} - */ - public NimbusJwtDecoder build() { - return new NimbusJwtDecoder(processor()); - } - - } - /** * A builder for creating {@link NimbusJwtDecoder} instances based on a public key. */ @@ -903,4 +801,108 @@ public final class NimbusJwtDecoder implements JwtDecoder { } + /** + * A builder for creating {@link NimbusJwtDecoder} instances based on a + * {@code JWKSource}. + * + * @since 7.0 + */ + public static final class JwkSourceJwtDecoderBuilder { + + private static final JOSEObjectTypeVerifier NO_TYPE_VERIFIER = (header, context) -> { + }; + + private final Function, Set> defaultAlgorithms = (source) -> Set + .of(JWSAlgorithm.RS256); + + private final JOSEObjectTypeVerifier typeVerifier = NO_TYPE_VERIFIER; + + private final Set signatureAlgorithms = new HashSet<>(); + + private Consumer> jwtProcessorCustomizer; + + private final JWKSource jwkSource; + + private JwkSourceJwtDecoderBuilder(JWKSource jwkSource) { + Assert.notNull(jwkSource, "jwkSource cannot be null"); + this.jwkSource = jwkSource; + this.jwtProcessorCustomizer = (processor) -> { + }; + } + + /** + * Append the given signing + * algorithm to the set of algorithms to use. + * @param signatureAlgorithm the algorithm to use + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + */ + public JwkSourceJwtDecoderBuilder jwsAlgorithm(SignatureAlgorithm signatureAlgorithm) { + Assert.notNull(signatureAlgorithm, "signatureAlgorithm cannot be null"); + this.signatureAlgorithms.add(signatureAlgorithm); + return this; + } + + /** + * Configure the list of + * algorithms to use with the given {@link Consumer}. + * @param signatureAlgorithmsConsumer a {@link Consumer} for further configuring + * the algorithm list + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + */ + public JwkSourceJwtDecoderBuilder jwsAlgorithms(Consumer> signatureAlgorithmsConsumer) { + Assert.notNull(signatureAlgorithmsConsumer, "signatureAlgorithmsConsumer cannot be null"); + signatureAlgorithmsConsumer.accept(this.signatureAlgorithms); + return this; + } + + /** + * Use the given {@link Consumer} to customize the {@link JWTProcessor + * ConfigurableJWTProcessor} before passing it to the build + * {@link NimbusJwtDecoder}. + * @param jwtProcessorCustomizer the callback used to alter the processor + * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations + * @since 5.4 + */ + public JwkSourceJwtDecoderBuilder jwtProcessorCustomizer( + Consumer> jwtProcessorCustomizer) { + Assert.notNull(jwtProcessorCustomizer, "jwtProcessorCustomizer cannot be null"); + this.jwtProcessorCustomizer = jwtProcessorCustomizer; + return this; + } + + JWSKeySelector jwsKeySelector(JWKSource jwkSource) { + if (this.signatureAlgorithms.isEmpty()) { + return new JWSVerificationKeySelector<>(this.defaultAlgorithms.apply(jwkSource), jwkSource); + } + Set jwsAlgorithms = new HashSet<>(); + for (SignatureAlgorithm signatureAlgorithm : this.signatureAlgorithms) { + JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName()); + jwsAlgorithms.add(jwsAlgorithm); + } + return new JWSVerificationKeySelector<>(jwsAlgorithms, jwkSource); + } + + JWTProcessor processor() { + ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor<>(); + jwtProcessor.setJWSTypeVerifier(this.typeVerifier); + jwtProcessor.setJWSKeySelector(jwsKeySelector(this.jwkSource)); + // Spring Security validates the claim set independent from Nimbus + jwtProcessor.setJWTClaimsSetVerifier((claims, context) -> { + }); + this.jwtProcessorCustomizer.accept(jwtProcessor); + return jwtProcessor; + } + + /** + * Build the configured {@link NimbusJwtDecoder}. + * @return the configured {@link NimbusJwtDecoder} + */ + public NimbusJwtDecoder build() { + return new NimbusJwtDecoder(processor()); + } + + } + } From 9654e51bd4b3b556e824c739a45bee3dfa4c3e76 Mon Sep 17 00:00:00 2001 From: dae won Date: Fri, 30 May 2025 12:13:39 +0900 Subject: [PATCH 279/504] Include UsernameNotFoundException in BadCredentialsException Closes gh-16496 Signed-off-by: dae won --- .../dao/AbstractUserDetailsAuthenticationProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java b/core/src/main/java/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java index d107f9aa22..f0c5b2c50c 100644 --- a/core/src/main/java/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java +++ b/core/src/main/java/org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java @@ -137,11 +137,12 @@ public abstract class AbstractUserDetailsAuthenticationProvider } catch (UsernameNotFoundException ex) { this.logger.debug(LogMessage.format("Failed to find user '%s'", username)); + String message = this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", + "Bad credentials"); if (!this.hideUserNotFoundExceptions) { throw ex; } - throw new BadCredentialsException(this.messages - .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + throw new BadCredentialsException(message, ex); } Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); } From 5e56fc13bed27a01f55ff1b175b2a354d878e561 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:29:44 +0000 Subject: [PATCH 280/504] Bump io-spring-javaformat from 0.0.45 to 0.0.46 Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9c405db07d..6a5e4de9e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.45" +io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From b85814efcf7c951f450a03548ac17e6410365974 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:43:40 +0000 Subject: [PATCH 281/504] Bump io-spring-javaformat from 0.0.45 to 0.0.46 Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ca108e9b2..09758c77fa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.45" +io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From b20cfceabbd1fe9c019cfb724272f563ed667a63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:48:10 +0000 Subject: [PATCH 282/504] Bump io-spring-javaformat from 0.0.45 to 0.0.46 Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6a16532177..f5379aff42 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.45" +io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 9872997caded91f96191e55f3e37d306e0842a4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 04:05:48 +0000 Subject: [PATCH 283/504] Bump io-spring-javaformat from 0.0.45 to 0.0.46 Bumps `io-spring-javaformat` from 0.0.45 to 0.0.46. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.45 to 0.0.46 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.45...v0.0.46) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.46 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04b1cfa6b1..4138b9b43a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.45" +io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 8953f464fb2d50dde2a8e783e919b0f3b158b1ee Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Wed, 14 May 2025 16:54:52 +0700 Subject: [PATCH 284/504] Add Switch for Processing GET Requests Closes gh-17099 Signed-off-by: Tran Ngoc Nhan --- .../Saml2AuthenticationTokenConverter.java | 23 +++++++++++++++---- ...aml2AuthenticationTokenConverterTests.java | 17 +++++++++++++- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java index 8acc64bf97..73872bbe03 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,8 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo private Saml2AuthenticationRequestRepository authenticationRequestRepository; + private boolean shouldConvertGetRequests = true; + /** * Constructs a {@link Saml2AuthenticationTokenConverter} given a strategy for * resolving {@link RelyingPartyRegistration}s @@ -86,16 +88,27 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo this.authenticationRequestRepository = authenticationRequestRepository; } + /** + * Use the given {@code shouldConvertGetRequests} to convert {@code GET} requests. + * Default is {@code true}. + * @param shouldConvertGetRequests the {@code shouldConvertGetRequests} to use + * @since 7.0 + */ + public void setShouldConvertGetRequests(boolean shouldConvertGetRequests) { + this.shouldConvertGetRequests = shouldConvertGetRequests; + } + private String decode(HttpServletRequest request) { String encoded = request.getParameter(Saml2ParameterNames.SAML_RESPONSE); if (encoded == null) { return null; } + boolean isGet = HttpMethod.GET.matches(request.getMethod()); + if (!this.shouldConvertGetRequests && isGet) { + return null; + } try { - return Saml2Utils.withEncoded(encoded) - .requireBase64(true) - .inflate(HttpMethod.GET.matches(request.getMethod())) - .decode(); + return Saml2Utils.withEncoded(encoded).requireBase64(true).inflate(isGet).decode(); } catch (Exception ex) { throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, ex.getMessage()), diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverterTests.java index f54788a4ea..b023d38cb6 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -230,6 +230,21 @@ public class Saml2AuthenticationTokenConverterTests { .isThrownBy(() -> converter.setAuthenticationRequestRepository(null)); } + @Test + public void shouldNotConvertGetRequests() { + Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( + this.relyingPartyRegistrationResolver); + converter.setShouldConvertGetRequests(false); + given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any())) + .willReturn(this.relyingPartyRegistration); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + request.setParameter(Saml2ParameterNames.SAML_RESPONSE, + Saml2Utils.samlEncode("response".getBytes(StandardCharsets.UTF_8))); + Saml2AuthenticationToken token = converter.convert(request); + assertThat(token).isNull(); + } + private void validateSsoCircleXml(String xml) { assertThat(xml).contains("InResponseTo=\"ARQ9a73ead-7dcf-45a8-89eb-26f3c9900c36\"") .contains(" ID=\"s246d157446618e90e43fb79bdd4d9e9e19cf2c7c4\"") From 4ed131f6ab89ec5082fb78a1cfcc75258451e681 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:19:56 -0600 Subject: [PATCH 285/504] Add shouldConvertGetRequests Migration Steps Issue gh-17099 --- .../ROOT/pages/migration/servlet/oauth2.adoc | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc index 3caeec4133..e80e0a916e 100644 --- a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc +++ b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc @@ -78,3 +78,42 @@ fun jwtDecoder(): JwtDecoder { ====== <1> - `validateTypes` now defaults to `false` <2> - `JwtTypeValidator#jwt` is added by all `createDefaultXXX` methods + +== Do Not Process `` GET Requests with `Saml2AuthenticationTokenConverter` + +Spring Security does not support processing `` payloads over GET as this is not supported by the SAML 2.0 spec. + +To better comply with this, `Saml2AuthenticationTokenConverter` will not process GET requests by default as of Spring Security 8. +To prepare for this, the property `shouldConvertGetRequests` is available. +To use it, publish your own `Saml2AuthenticationTokenConverter` like so: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +Saml2AuthenticationTokenConverter authenticationConverter(RelyingPartyRegistrationRepository registrations) { + Saml2AuhenticationTokenConverter authenticationConverter = new Saml2AuthenticationTokenConverter( + new DefaultRelyingPartyRegistrationResolver(registrations)); + authenticationConverter.setShouldConvertGetRequests(false); + return authenticationConverter; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationConverter(val registrations: RelyingPartyRegistrationRepository): Saml2AuthenticationTokenConverter { + val authenticationConverter = new Saml2AuthenticationTokenConverter( + DefaultRelyingPartyRegistrationResolver(registrations)) + authenticationConverter.setShouldConvertGetRequests(false) + return authenticationConverter +} +---- +====== + +If you must continue using `Saml2AuthenticationTokenConverter` to process GET requests, you can call `setShouldConvertGetRequests` to `true.` From 3de7312658b7f76d88b346d077f700ab654b7fff Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:56:45 -0600 Subject: [PATCH 286/504] Add Saml2Error Static Factories --- .../security/saml2/core/Saml2Error.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2Error.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2Error.java index 6709092ced..4e6653b9b5 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2Error.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2Error.java @@ -51,6 +51,66 @@ public class Saml2Error implements Serializable { this.description = description; } + /** + * Construct an {@link Saml2ErrorCodes#INVALID_RESPONSE} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error invalidResponse(String description) { + return new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, description); + } + + /** + * Construct an {@link Saml2ErrorCodes#INTERNAL_VALIDATION_ERROR} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error internalValidationError(String description) { + return new Saml2Error(Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR, description); + } + + /** + * Construct an {@link Saml2ErrorCodes#MALFORMED_RESPONSE_DATA} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error malformedResponseData(String description) { + return new Saml2Error(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, description); + } + + /** + * Construct an {@link Saml2ErrorCodes#DECRYPTION_ERROR} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error decryptionError(String description) { + return new Saml2Error(Saml2ErrorCodes.DECRYPTION_ERROR, description); + } + + /** + * Construct an {@link Saml2ErrorCodes#RELYING_PARTY_REGISTRATION_NOT_FOUND} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error relyingPartyRegistrationNotFound(String description) { + return new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND, description); + } + + /** + * Construct an {@link Saml2ErrorCodes#SUBJECT_NOT_FOUND} error + * @param description the error description + * @return the resulting {@link Saml2Error} + * @since 7.0 + */ + public static Saml2Error subjectNotFound(String description) { + return new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, description); + } + /** * Returns the error code. * @return the error code From 32c7e8a6eecdb6a55da15c3d06f102b07d81ce86 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:56:56 -0600 Subject: [PATCH 287/504] Use Saml2Error Static Factories --- .../BaseOpenSamlAuthenticationProvider.java | 15 +++++---------- .../BaseOpenSamlAuthenticationTokenConverter.java | 4 +--- .../web/Saml2AuthenticationTokenConverter.java | 7 +++---- ...lLogoutRequestValidatorParametersResolver.java | 4 +--- .../logout/Saml2LogoutRequestFilter.java | 4 +--- .../web/OpenSamlAuthenticationTokenConverter.java | 4 +--- ...lLogoutRequestValidatorParametersResolver.java | 4 +--- .../OpenSaml5AuthenticationProvider.java | 4 ++-- 8 files changed, 15 insertions(+), 31 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java index 32b4fa61ec..b02f82062d 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java @@ -302,7 +302,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { throw ex; } catch (Exception ex) { - throw createAuthenticationException(Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR, ex.getMessage(), ex); + throw new Saml2AuthenticationException(Saml2Error.internalValidationError(ex.getMessage()), ex); } } @@ -316,7 +316,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return this.saml.deserialize(response); } catch (Exception ex) { - throw createAuthenticationException(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, ex.getMessage(), ex); + throw new Saml2AuthenticationException(Saml2Error.malformedResponseData(ex.getMessage()), ex); } } @@ -375,7 +375,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { .debug("Found " + errors.size() + " validation errors in SAML response [" + response.getID() + "]"); } Saml2Error first = errors.iterator().next(); - throw createAuthenticationException(first.getErrorCode(), first.getDescription(), null); + throw new Saml2AuthenticationException(first); } else { if (this.logger.isDebugEnabled()) { @@ -408,7 +408,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { this.saml.withDecryptionKeys(registration.getDecryptionX509Credentials()).decrypt(response); } catch (Exception ex) { - throw createAuthenticationException(Saml2ErrorCodes.DECRYPTION_ERROR, ex.getMessage(), ex); + throw new Saml2AuthenticationException(Saml2Error.decryptionError(ex.getMessage()), ex); } }; } @@ -437,7 +437,7 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { this.saml.withDecryptionKeys(registration.getDecryptionX509Credentials()).decrypt(assertion); } catch (Exception ex) { - throw createAuthenticationException(Saml2ErrorCodes.DECRYPTION_ERROR, ex.getMessage(), ex); + throw new Saml2AuthenticationException(Saml2Error.decryptionError(ex.getMessage()), ex); } }; } @@ -503,11 +503,6 @@ class BaseOpenSamlAuthenticationProvider implements AuthenticationProvider { return xmlObject; } - private static Saml2AuthenticationException createAuthenticationException(String code, String message, - Exception cause) { - return new Saml2AuthenticationException(new Saml2Error(code, message), cause); - } - private static Converter createAssertionValidator(String errorCode, Converter validatorConverter, Converter contextConverter) { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java index a88847aeb6..1643959155 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java @@ -22,7 +22,6 @@ import org.opensaml.saml.saml2.core.Response; import org.springframework.http.HttpMethod; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -182,8 +181,7 @@ final class BaseOpenSamlAuthenticationTokenConverter implements AuthenticationCo .decode(); } catch (Exception ex) { - throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, ex.getMessage()), - ex); + throw new Saml2AuthenticationException(Saml2Error.invalidResponse(ex.getMessage()), ex); } } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java index 73872bbe03..9a43edce6e 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/Saml2AuthenticationTokenConverter.java @@ -20,7 +20,6 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpMethod; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -107,12 +106,12 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo if (!this.shouldConvertGetRequests && isGet) { return null; } + Saml2Utils.DecodingConfigurer decoding = Saml2Utils.withEncoded(encoded).requireBase64(true).inflate(isGet); try { - return Saml2Utils.withEncoded(encoded).requireBase64(true).inflate(isGet).decode(); + return decoding.decode(); } catch (Exception ex) { - throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, ex.getMessage()), - ex); + throw new Saml2AuthenticationException(Saml2Error.invalidResponse(ex.getMessage()), ex); } } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java index 2e58340aef..84a53005aa 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java @@ -23,7 +23,6 @@ import org.springframework.http.HttpMethod; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -145,8 +144,7 @@ final class BaseOpenSamlLogoutRequestValidatorParametersResolver RelyingPartyRegistration registration = this.registrations.findByRegistrationId(registrationId); if (registration == null) { throw new Saml2AuthenticationException( - new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND, "registration not found"), - "registration not found"); + Saml2Error.relyingPartyRegistrationNotFound("registration not found")); } return logoutRequestByRegistration(request, registration, authentication); } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java index fd68bbc3a9..1476f37624 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java @@ -31,7 +31,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -268,8 +267,7 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { registrationId); if (registration == null) { throw new Saml2AuthenticationException( - new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND, "registration not found"), - "registration not found"); + Saml2Error.relyingPartyRegistrationNotFound("registration not found")); } UriResolver uriResolver = RelyingPartyRegistrationPlaceholderResolvers.uriResolver(request, registration); String entityId = uriResolver.resolve(registration.getEntityId()); diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSamlAuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSamlAuthenticationTokenConverter.java index 16f8908fd9..c680f93bb3 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSamlAuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSamlAuthenticationTokenConverter.java @@ -24,7 +24,6 @@ import org.opensaml.saml.saml2.core.Response; import org.springframework.http.HttpMethod; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -197,8 +196,7 @@ public final class OpenSamlAuthenticationTokenConverter implements Authenticatio .decode(); } catch (Exception ex) { - throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, ex.getMessage()), - ex); + throw new Saml2AuthenticationException(Saml2Error.invalidResponse(ex.getMessage()), ex); } } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java index 27a610a896..aae95e28c7 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java @@ -27,7 +27,6 @@ import org.springframework.http.HttpMethod; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; -import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -159,8 +158,7 @@ public final class OpenSamlLogoutRequestValidatorParametersResolver RelyingPartyRegistration registration = this.registrations.findByRegistrationId(registrationId); if (registration == null) { throw new Saml2AuthenticationException( - new Saml2Error(Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND, "registration not found"), - "registration not found"); + Saml2Error.relyingPartyRegistrationNotFound("registration not found")); } return logoutRequestByRegistration(request, registration, authentication); } diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java index e3cde7974e..d2dbb5ba0c 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java @@ -935,8 +935,8 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv private static String authenticatedPrincipal(Assertion assertion) { if (!BaseOpenSamlAuthenticationProvider.hasName(assertion)) { - throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND, - "Assertion [" + assertion.getID() + "] is missing a subject")); + throw new Saml2AuthenticationException( + Saml2Error.subjectNotFound("Assertion [" + assertion.getID() + "] is missing a subject")); } return assertion.getSubject().getNameID().getValue(); } From f73f253beb4bddbbabe1abe9bc58737a3ca82b6f Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:03:21 -0600 Subject: [PATCH 288/504] Add Switch for Processing GET Requests Issue gh-17099 --- ...BaseOpenSamlAuthenticationTokenConverter.java | 16 ++++++++++++---- .../OpenSaml4AuthenticationTokenConverter.java | 10 ++++++++++ .../OpenSaml5AuthenticationTokenConverter.java | 10 ++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java index 1643959155..e47ff4f48f 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/BaseOpenSamlAuthenticationTokenConverter.java @@ -51,6 +51,8 @@ final class BaseOpenSamlAuthenticationTokenConverter implements AuthenticationCo private Saml2AuthenticationRequestRepository authenticationRequests = new HttpSessionSaml2AuthenticationRequestRepository(); + private boolean shouldConvertGetRequests = true; + /** * Constructs a {@link BaseOpenSamlAuthenticationTokenConverter} given a repository * for {@link RelyingPartyRegistration}s @@ -172,13 +174,19 @@ final class BaseOpenSamlAuthenticationTokenConverter implements AuthenticationCo this.requestMatcher = requestMatcher; } + void setShouldConvertGetRequests(boolean shouldConvertGetRequests) { + this.shouldConvertGetRequests = shouldConvertGetRequests; + } + private String decode(HttpServletRequest request) { String encoded = request.getParameter(Saml2ParameterNames.SAML_RESPONSE); + boolean isGet = HttpMethod.GET.matches(request.getMethod()); + if (!this.shouldConvertGetRequests && isGet) { + return null; + } + Saml2Utils.DecodingConfigurer decoding = Saml2Utils.withEncoded(encoded).requireBase64(true).inflate(isGet); try { - return Saml2Utils.withEncoded(encoded) - .requireBase64(true) - .inflate(HttpMethod.GET.matches(request.getMethod())) - .decode(); + return decoding.decode(); } catch (Exception ex) { throw new Saml2AuthenticationException(Saml2Error.invalidResponse(ex.getMessage()), ex); diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4AuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4AuthenticationTokenConverter.java index 70186f03d0..e82ecea767 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4AuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4AuthenticationTokenConverter.java @@ -101,4 +101,14 @@ public final class OpenSaml4AuthenticationTokenConverter implements Authenticati this.delegate.setRequestMatcher(requestMatcher); } + /** + * Use the given {@code shouldConvertGetRequests} to convert {@code GET} requests. + * Default is {@code true}. + * @param shouldConvertGetRequests the {@code shouldConvertGetRequests} to use + * @since 7.0 + */ + public void setShouldConvertGetRequests(boolean shouldConvertGetRequests) { + this.delegate.setShouldConvertGetRequests(shouldConvertGetRequests); + } + } diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5AuthenticationTokenConverter.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5AuthenticationTokenConverter.java index 48a2bd35a2..570718b7cf 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5AuthenticationTokenConverter.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5AuthenticationTokenConverter.java @@ -101,4 +101,14 @@ public final class OpenSaml5AuthenticationTokenConverter implements Authenticati this.delegate.setRequestMatcher(requestMatcher); } + /** + * Use the given {@code shouldConvertGetRequests} to convert {@code GET} requests. + * Default is {@code true}. + * @param shouldConvertGetRequests the {@code shouldConvertGetRequests} to use + * @since 7.0 + */ + public void setShouldConvertGetRequests(boolean shouldConvertGetRequests) { + this.delegate.setShouldConvertGetRequests(shouldConvertGetRequests); + } + } From 492444c5882c118eb8d8a538d8a628521cd58b2d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:08:51 -0600 Subject: [PATCH 289/504] Update shouldConvertGetRequests Migration Steps Issue gh-17099 --- .../ROOT/pages/migration/servlet/oauth2.adoc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc index e80e0a916e..6cdb9043dd 100644 --- a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc +++ b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc @@ -83,9 +83,9 @@ fun jwtDecoder(): JwtDecoder { Spring Security does not support processing `` payloads over GET as this is not supported by the SAML 2.0 spec. -To better comply with this, `Saml2AuthenticationTokenConverter` will not process GET requests by default as of Spring Security 8. +To better comply with this, `Saml2AuthenticationTokenConverter`, `OpenSaml4AuthenticationTokenConverter`, and `OpenSaml5AuthenticationTokenConverter` will not process GET requests by default as of Spring Security 8. To prepare for this, the property `shouldConvertGetRequests` is available. -To use it, publish your own `Saml2AuthenticationTokenConverter` like so: +To use it, publish your own converter like so: [tabs] ====== @@ -94,9 +94,8 @@ Java:: [source,java,role="primary"] ---- @Bean -Saml2AuthenticationTokenConverter authenticationConverter(RelyingPartyRegistrationRepository registrations) { - Saml2AuhenticationTokenConverter authenticationConverter = new Saml2AuthenticationTokenConverter( - new DefaultRelyingPartyRegistrationResolver(registrations)); +OpenSaml5AuthenticationTokenConverter authenticationConverter(RelyingPartyRegistrationRepository registrations) { + OpenSaml5AuthenticationTokenConverter authenticationConverter = new OpenSaml5AuthenticationTokenConverter(registrations); authenticationConverter.setShouldConvertGetRequests(false); return authenticationConverter; } @@ -108,12 +107,11 @@ Kotlin:: ---- @Bean fun authenticationConverter(val registrations: RelyingPartyRegistrationRepository): Saml2AuthenticationTokenConverter { - val authenticationConverter = new Saml2AuthenticationTokenConverter( - DefaultRelyingPartyRegistrationResolver(registrations)) + val authenticationConverter = Saml2AuthenticationTokenConverter(registrations) authenticationConverter.setShouldConvertGetRequests(false) return authenticationConverter } ---- ====== -If you must continue using `Saml2AuthenticationTokenConverter` to process GET requests, you can call `setShouldConvertGetRequests` to `true.` +If you must continue using `Saml2AuthenticationTokenConverter`, `OpenSaml4AuthenticationTokenConverter`, or `OpenSaml5AuthenticationTokenConverter` to process GET requests, you can call `setShouldConvertGetRequests` to `true.` From 1b081b0628da517213be1b41c86037a3a34244fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 03:44:50 +0000 Subject: [PATCH 290/504] Bump io.spring.develocity.conventions from 0.0.22 to 0.0.23 Bumps [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions) from 0.0.22 to 0.0.23. - [Release notes](https://github.com/spring-io/develocity-conventions/releases) - [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.22...v0.0.23) --- updated-dependencies: - dependency-name: io.spring.develocity.conventions dependency-version: 0.0.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 74cb46b16b..a1af657b56 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ pluginManagement { } plugins { - id "io.spring.develocity.conventions" version "0.0.22" + id "io.spring.develocity.conventions" version "0.0.23" } dependencyResolutionManagement { From 0ec7a7a30562dc86f117faaadaf88b0cce81ca9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 03:47:25 +0000 Subject: [PATCH 291/504] Bump io.spring.develocity.conventions from 0.0.22 to 0.0.23 Bumps [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions) from 0.0.22 to 0.0.23. - [Release notes](https://github.com/spring-io/develocity-conventions/releases) - [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.22...v0.0.23) --- updated-dependencies: - dependency-name: io.spring.develocity.conventions dependency-version: 0.0.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 74cb46b16b..a1af657b56 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ pluginManagement { } plugins { - id "io.spring.develocity.conventions" version "0.0.22" + id "io.spring.develocity.conventions" version "0.0.23" } dependencyResolutionManagement { From 7341e629cbe2de6bededb90c2b91bad7480ac47d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 03:49:51 +0000 Subject: [PATCH 292/504] Bump io.spring.develocity.conventions from 0.0.22 to 0.0.23 Bumps [io.spring.develocity.conventions](https://github.com/spring-io/develocity-conventions) from 0.0.22 to 0.0.23. - [Release notes](https://github.com/spring-io/develocity-conventions/releases) - [Commits](https://github.com/spring-io/develocity-conventions/compare/v0.0.22...v0.0.23) --- updated-dependencies: - dependency-name: io.spring.develocity.conventions dependency-version: 0.0.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 6ebece46a8..043010de2b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ pluginManagement { } plugins { - id "io.spring.develocity.conventions" version "0.0.22" + id "io.spring.develocity.conventions" version "0.0.23" } dependencyResolutionManagement { From 33ae1711a76acc0eafa93ccf40d1ad7c09a35830 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Sat, 31 May 2025 05:05:15 +0300 Subject: [PATCH 293/504] Set Precedence Order for Spring MVC TargetVisitor Closes gh-17185 Signed-off-by: Evgeniy Cheban --- .../AuthorizationProxyWebConfiguration.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java index 4af062ef96..d6cdea7279 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/AuthorizationProxyWebConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import org.springframework.core.Ordered; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; @@ -37,7 +38,9 @@ class AuthorizationProxyWebConfiguration { return new WebTargetVisitor(); } - static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor { + static class WebTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor, Ordered { + + private static final int DEFAULT_ORDER = 100; @Override public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { @@ -60,6 +63,11 @@ class AuthorizationProxyWebConfiguration { return null; } + @Override + public int getOrder() { + return DEFAULT_ORDER; + } + } } From 4967f3feee0b0f5906132eb3467fff3860688463 Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 11 Apr 2025 15:26:00 +0300 Subject: [PATCH 294/504] Add Support BearerTokenAuthenticationConverter Closes gh-14750 Signed-off-by: Max Batischev --- .../OAuth2ResourceServerConfigurer.java | 97 ++++++++-- ...th2ResourceServerBeanDefinitionParser.java | 76 +++++++- .../security/config/spring-security-6.5.rnc | 3 + .../security/config/spring-security-6.5.xsd | 6 + .../OAuth2ResourceServerConfigurerTests.java | 83 +++++++- ...sourceServerBeanDefinitionParserTests.java | 41 ++-- ...ionParserTests-AuthenticationConverter.xml | 32 ++++ ...icationConverterAndBearerTokenResolver.xml | 32 ++++ ...arserTests-MockAuthenticationConverter.xml | 27 +++ .../servlet/appendix/namespace/http.adoc | 4 + .../resource/web/BearerTokenResolver.java | 5 +- .../BearerTokenAuthenticationConverter.java | 181 ++++++++++++++++++ .../BearerTokenAuthenticationFilter.java | 35 +++- ...arerTokenAuthenticationConverterTests.java | 148 ++++++++++++++ .../BearerTokenAuthenticationFilterTests.java | 10 + 15 files changed, 722 insertions(+), 58 deletions(-) create mode 100644 config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverter.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverterAndBearerTokenResolver.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MockAuthenticationConverter.xml create mode 100644 oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java create mode 100644 oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index e9a425d46d..8d44dfdcb5 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -23,6 +23,8 @@ import java.util.Map; import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.core.convert.converter.Converter; @@ -37,10 +39,12 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; @@ -49,13 +53,14 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; -import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler; +import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter; import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandlerImpl; import org.springframework.security.web.access.DelegatingAccessDeniedHandler; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.csrf.CsrfException; import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; @@ -64,6 +69,7 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.web.accept.ContentNegotiationStrategy; import org.springframework.web.accept.HeaderContentNegotiationStrategy; @@ -156,7 +162,7 @@ public final class OAuth2ResourceServerConfigurer authenticationManagerResolver; - private BearerTokenResolver bearerTokenResolver; + private AuthenticationConverter authenticationConverter; private JwtConfigurer jwtConfigurer; @@ -194,9 +200,25 @@ public final class OAuth2ResourceServerConfigurer bearerTokenResolver(BearerTokenResolver bearerTokenResolver) { Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); - this.bearerTokenResolver = bearerTokenResolver; + this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); + return this; + } + + /** + * Sets the {@link AuthenticationConverter} to use. + * @param authenticationConverter the authentication converter + * @return the {@link OAuth2ResourceServerConfigurer} for further configuration + * @since 6.5 + */ + public OAuth2ResourceServerConfigurer authenticationConverter(AuthenticationConverter authenticationConverter) { + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + this.authenticationConverter = authenticationConverter; return this; } @@ -271,8 +293,6 @@ public final class OAuth2ResourceServerConfigurer 0) { - this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); - } - else { - this.bearerTokenResolver = new DefaultBearerTokenResolver(); - } + AuthenticationConverter getAuthenticationConverter() { + if (this.authenticationConverter != null) { + return this.authenticationConverter; } - return this.bearerTokenResolver; + if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) { + this.authenticationConverter = this.context.getBean(AuthenticationConverter.class); + } + else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { + BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); + this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); + } + else { + this.authenticationConverter = new BearerTokenAuthenticationConverter(); + } + return this.authenticationConverter; + } + + BearerTokenResolver getBearerTokenResolver() { + AuthenticationConverter authenticationConverter = getAuthenticationConverter(); + if (authenticationConverter instanceof BearerTokenResolverAuthenticationConverterAdapter bearer) { + return bearer.bearerTokenResolver; + } + return null; } public class JwtConfigurer { @@ -560,21 +595,43 @@ public final class OAuth2ResourceServerConfigurer + + + Reference to a AuthenticationConverter + + + diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 6b263c7048..5c655f5afd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -127,12 +127,14 @@ import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthen import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler; +import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter; import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandlerImpl; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultMatcher; @@ -759,13 +761,6 @@ public class OAuth2ResourceServerConfigurerTests { assertThat(oauth2.getBearerTokenResolver()).isEqualTo(resolver); } - @Test - public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() { - ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext(); - OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context); - assertThat(oauth2.getBearerTokenResolver()).isInstanceOf(DefaultBearerTokenResolver.class); - } - @Test public void requestWhenCustomAuthenticationDetailsSourceThenUsed() throws Exception { this.spring.register(CustomAuthenticationDetailsSource.class, JwtDecoderConfig.class, BasicController.class) @@ -1415,6 +1410,47 @@ public class OAuth2ResourceServerConfigurerTests { verify(authenticationConverter).convert(any(), any()); } + @Test + public void getAuthenticationConverterWhenDuplicateConverterBeansAndAnotherOnTheDslThenTheDslOneIsUsed() { + AuthenticationConverter converter = mock(AuthenticationConverter.class); + AuthenticationConverter converterBean = mock(AuthenticationConverter.class); + GenericWebApplicationContext context = new GenericWebApplicationContext(); + context.registerBean("converterOne", AuthenticationConverter.class, () -> converterBean); + context.registerBean("converterTwo", AuthenticationConverter.class, () -> converterBean); + this.spring.context(context).autowire(); + OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context); + oauth2.authenticationConverter(converter); + assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter); + } + + @Test + public void getAuthenticationConverterWhenConverterBeanAndAnotherOnTheDslThenTheDslOneIsUsed() { + AuthenticationConverter converter = mock(AuthenticationConverter.class); + AuthenticationConverter converterBean = mock(AuthenticationConverter.class); + GenericWebApplicationContext context = new GenericWebApplicationContext(); + context.registerBean(AuthenticationConverter.class, () -> converterBean); + this.spring.context(context).autowire(); + OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context); + oauth2.authenticationConverter(converter); + assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter); + } + + @Test + public void getAuthenticationConverterWhenDuplicateConverterBeansThenWiringException() { + assertThatExceptionOfType(BeanCreationException.class) + .isThrownBy( + () -> this.spring.register(MultipleAuthenticationConverterBeansConfig.class, JwtDecoderConfig.class) + .autowire()) + .withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class); + } + + @Test + public void getAuthenticationConverterWhenNoConverterSpecifiedThenTheDefaultIsUsed() { + ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext(); + OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context); + assertThat(oauth2.getAuthenticationConverter()).isInstanceOf(BearerTokenAuthenticationConverter.class); + } + private static void registerMockBean(GenericApplicationContext context, String name, Class clazz) { context.registerBean(name, clazz, () -> mock(clazz)); } @@ -2516,6 +2552,39 @@ public class OAuth2ResourceServerConfigurerTests { } + @Configuration + @EnableWebSecurity + static class MultipleAuthenticationConverterBeansConfig { + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().authenticated() + .and() + .oauth2ResourceServer() + .jwt(); + return http.build(); + // @formatter:on + } + + @Bean + AuthenticationConverter authenticationConverterOne() { + BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); + converter.setAllowUriQueryParameter(true); + return converter; + } + + @Bean + AuthenticationConverter authenticationConverterTwo() { + BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); + converter.setAllowUriQueryParameter(true); + return converter; + } + + } + @Configuration @EnableWebSecurity static class MultipleIssuersConfig { diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java index 6a01051ca4..5ad167eef8 100644 --- a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import java.time.Instant; import java.time.ZoneId; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; @@ -50,13 +49,11 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.w3c.dom.Element; -import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanReference; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.XmlReaderContext; @@ -85,12 +82,14 @@ import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.oauth2.jwt.TestJwts; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -462,6 +461,24 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { verify(bearerTokenResolver).resolve(any(HttpServletRequest.class)); } + @Test + public void getWhenCustomAuthenticationConverterThenUses() throws Exception { + this.spring + .configLocations(xml("MockAuthenticationConverter"), xml("MockJwtDecoder"), xml("AuthenticationConverter")) + .autowire(); + JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); + given(decoder.decode("token")).willReturn(TestJwts.jwt().build()); + AuthenticationConverter authenticationConverter = this.spring.getContext() + .getBean(AuthenticationConverter.class); + given(authenticationConverter.convert(any(HttpServletRequest.class))) + .willReturn(new BearerTokenAuthenticationToken("token")); + + this.mvc.perform(get("/")).andExpect(status().isNotFound()); + + verify(decoder).decode("token"); + verify(authenticationConverter).convert(any(HttpServletRequest.class)); + } + @Test public void requestWhenBearerTokenResolverAllowsRequestBodyThenEitherHeaderOrRequestBodyIsAccepted() throws Exception { @@ -521,14 +538,6 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { // @formatter:on } - @Test - public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() { - OAuth2ResourceServerBeanDefinitionParser oauth2 = new OAuth2ResourceServerBeanDefinitionParser( - mock(BeanReference.class), mock(List.class), mock(Map.class), mock(Map.class), mock(List.class), - mock(BeanMetadataElement.class)); - assertThat(oauth2.getBearerTokenResolver(mock(Element.class))).isInstanceOf(RootBeanDefinition.class); - } - @Test public void requestWhenCustomJwtDecoderThenUsed() throws Exception { this.spring.configLocations(xml("MockJwtDecoder"), xml("Jwt")).autowire(); @@ -545,6 +554,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { .isThrownBy(() -> this.spring.configLocations(xml("JwtDecoderAndJwkSetUri")).autowire()); } + @Test + public void configureWhenAuthenticationConverterAndJwkSetUriThenException() { + assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy( + () -> this.spring.configLocations(xml("AuthenticationConverterAndBearerTokenResolver")).autowire()); + } + @Test public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception { this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire(); diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverter.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverter.xml new file mode 100644 index 0000000000..04d3932f09 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverter.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverterAndBearerTokenResolver.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverterAndBearerTokenResolver.xml new file mode 100644 index 0000000000..c0cb49bf65 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-AuthenticationConverterAndBearerTokenResolver.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MockAuthenticationConverter.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MockAuthenticationConverter.xml new file mode 100644 index 0000000000..397c4c59bf --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MockAuthenticationConverter.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 2b434d4303..d5438e0f43 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -1272,6 +1272,10 @@ Reference to a `BearerTokenResolver` which will retrieve the bearer token from t * **entry-point-ref** Reference to a `AuthenticationEntryPoint` which will handle unauthorized requests +[[nsa-oauth2-resource-server-authentication-converter-ref]] +* **authentication-converter-ref** +Reference to a `AuthenticationConverter` which convert request to authentication + [[nsa-jwt]] == Represents an OAuth 2.0 Resource Server that will authorize JWTs diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java index 7abd174630..0fd023c5f6 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,10 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; * @since 5.1 * @see RFC 6750 * Section 2: Authenticated Requests + * @deprecated Use + * {@link org.springframework.security.web.authentication.AuthenticationConverter} instead */ +@Deprecated @FunctionalInterface public interface BearerTokenResolver { diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java new file mode 100644 index 0000000000..211a49bf21 --- /dev/null +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java @@ -0,0 +1,181 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.server.resource.web.authentication; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.AuthenticationDetailsSource; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.server.resource.BearerTokenError; +import org.springframework.security.oauth2.server.resource.BearerTokenErrors; +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.web.authentication.AuthenticationConverter; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Implementation of {@link AuthenticationConverter}, that converts request to + * {@link BearerTokenAuthenticationToken} + * + * @author Max Batischev + * @since 6.5 + */ +public final class BearerTokenAuthenticationConverter implements AuthenticationConverter { + + private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); + + private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+=*)$", + Pattern.CASE_INSENSITIVE); + + private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token"; + + private boolean allowFormEncodedBodyParameter = false; + + private boolean allowUriQueryParameter = false; + + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; + + @Override + public Authentication convert(HttpServletRequest request) { + String token = resolveToken(request); + if (StringUtils.hasText(token)) { + BearerTokenAuthenticationToken authenticationToken = new BearerTokenAuthenticationToken(token); + authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request)); + + return authenticationToken; + } + return null; + } + + private String resolveToken(HttpServletRequest request) { + final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); + final String parameterToken = isParameterTokenSupportedForRequest(request) + ? resolveFromRequestParameters(request) : null; + if (authorizationHeaderToken != null) { + if (parameterToken != null) { + final BearerTokenError error = BearerTokenErrors + .invalidRequest("Found multiple bearer tokens in the request"); + throw new OAuth2AuthenticationException(error); + } + return authorizationHeaderToken; + } + if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { + return parameterToken; + } + return null; + } + + private String resolveFromAuthorizationHeader(HttpServletRequest request) { + String authorization = request.getHeader(this.bearerTokenHeaderName); + if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { + return null; + } + Matcher matcher = authorizationPattern.matcher(authorization); + if (!matcher.matches()) { + BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); + throw new OAuth2AuthenticationException(error); + } + return matcher.group("token"); + } + + private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) { + return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request) + && !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request))); + } + + private static String resolveFromRequestParameters(HttpServletRequest request) { + String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME); + if (values == null || values.length == 0) { + return null; + } + if (values.length == 1) { + return values[0]; + } + BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); + throw new OAuth2AuthenticationException(error); + } + + private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) { + return isFormEncodedRequest(request) || isGetRequest(request); + } + + private boolean isGetRequest(HttpServletRequest request) { + return HttpMethod.GET.name().equals(request.getMethod()); + } + + private boolean isFormEncodedRequest(HttpServletRequest request) { + return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()); + } + + private static boolean hasAccessTokenInQueryString(HttpServletRequest request) { + return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME); + } + + /** + * Set if transport of access token using URI query parameter is supported. Defaults + * to {@code false}. + * + * The spec recommends against using this mechanism for sending bearer tokens, and + * even goes as far as stating that it was only included for completeness. + * @param allowUriQueryParameter if the URI query parameter is supported + */ + public void setAllowUriQueryParameter(boolean allowUriQueryParameter) { + this.allowUriQueryParameter = allowUriQueryParameter; + } + + /** + * Set this value to configure what header is checked when resolving a Bearer Token. + * This value is defaulted to {@link HttpHeaders#AUTHORIZATION}. + * + * This allows other headers to be used as the Bearer Token source such as + * {@link HttpHeaders#PROXY_AUTHORIZATION} + * @param bearerTokenHeaderName the header to check when retrieving the Bearer Token. + */ + public void setBearerTokenHeaderName(String bearerTokenHeaderName) { + this.bearerTokenHeaderName = bearerTokenHeaderName; + } + + /** + * Set if transport of access token using form-encoded body parameter is supported. + * Defaults to {@code false}. + * @param allowFormEncodedBodyParameter if the form-encoded body parameter is + * supported + */ + public void setAllowFormEncodedBodyParameter(boolean allowFormEncodedBodyParameter) { + this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter; + } + + /** + * Set the {@link AuthenticationDetailsSource} to use. Defaults to + * {@link WebAuthenticationDetailsSource}. + * @param authenticationDetailsSource the {@code AuthenticationDetailsSource} to use + */ + public void setAuthenticationDetailsSource( + AuthenticationDetailsSource authenticationDetailsSource) { + Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null"); + this.authenticationDetailsSource = authenticationDetailsSource; + } + +} diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java index 9cad61d0cb..5aa819f6be 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java @@ -44,6 +44,7 @@ import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthen import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; @@ -83,12 +84,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { private AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler( (request, response, exception) -> this.authenticationEntryPoint.commence(request, response, exception)); - private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver(); - private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); private SecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository(); + private AuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter(); + /** * Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s) * @param authenticationManagerResolver @@ -121,24 +122,22 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String token; + Authentication authenticationRequest; try { - token = this.bearerTokenResolver.resolve(request); + authenticationRequest = this.authenticationConverter.convert(request); } catch (OAuth2AuthenticationException invalid) { this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid); this.authenticationEntryPoint.commence(request, response, invalid); return; } - if (token == null) { + + if (authenticationRequest == null) { this.logger.trace("Did not process request since did not find bearer token"); filterChain.doFilter(request, response); return; } - BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token); - authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); - try { AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request); Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest); @@ -194,7 +193,14 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { */ public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) { Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); - this.bearerTokenResolver = bearerTokenResolver; + this.authenticationConverter = (request) -> { + String token = bearerTokenResolver.resolve(request); + if (!StringUtils.hasText(token)) { + this.logger.trace("Did not process request since did not find bearer token"); + return null; + } + return new BearerTokenAuthenticationToken(token); + }; } /** @@ -243,4 +249,15 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { return StringUtils.hasText(jwkThumbprintClaim); } + /** + * Set the {@link AuthenticationConverter} to use. Defaults to + * {@link BearerTokenAuthenticationConverter}. + * @param authenticationConverter the {@code AuthenticationConverter} to use + * @since 6.5 + */ + public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + this.authenticationConverter = authenticationConverter; + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java new file mode 100644 index 0000000000..a5655a0c11 --- /dev/null +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java @@ -0,0 +1,148 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.server.resource.web.authentication; + +import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.authentication.AuthenticationDetailsSource; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link BearerTokenAuthenticationConverter} + * + * @author Max Batischev + */ +public class BearerTokenAuthenticationConverterTests { + + private static final String X_AUTH_TOKEN_HEADER = "X-Auth-Token"; + + private static final String TEST_X_AUTH_TOKEN = "test-x-auth-token"; + + private static final String BEARER_TOKEN = "test_bearer_token"; + + private final BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); + + @Test + public void convertWhenAuthorizationHeaderIsPresentThenTokenIsConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN); + + Authentication authentication = this.converter.convert(request); + + assertThat(authentication).isNotNull(); + } + + @Test + public void convertWhenQueryParameterIsPresentThenTokenIsConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod(HttpMethod.GET.name()); + request.addParameter("access_token", BEARER_TOKEN); + + this.converter.setAllowUriQueryParameter(true); + + Authentication authentication = this.converter.convert(request); + assertThat(authentication).isNotNull(); + } + + @Test + public void convertWhenAuthorizationHeaderNotIsPresentThenTokenIsNotConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + + Authentication authentication = this.converter.convert(request); + + assertThat(authentication).isNull(); + } + + @Test + public void convertWhenAuthorizationHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("access_token", BEARER_TOKEN); + request.setMethod(HttpMethod.GET.name()); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request)) + .withMessageContaining("Found multiple bearer tokens in the request"); + } + + @Test + public void convertWhenXAuthTokenHeaderIsPresentAndBearerTokenHeaderNameSetThenTokenIsConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(X_AUTH_TOKEN_HEADER, "Bearer " + TEST_X_AUTH_TOKEN); + + this.converter.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER); + + Authentication authentication = this.converter.convert(request); + assertThat(authentication).isNotNull(); + } + + @Test + public void convertWhenHeaderWithMissingTokenIsPresentThenAuthenticationExceptionIsThrown() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer "); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request)) + .withMessageContaining(("Bearer token is malformed")); + } + + @Test + public void convertWhenHeaderWithInvalidCharactersIsPresentThenAuthenticationExceptionIsThrown() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer an\"invalid\"token"); + + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request)) + .withMessageContaining(("Bearer token is malformed")); + } + + @Test + @SuppressWarnings("unchecked") + public void convertWhenCustomAuthenticationDetailsSourceSetThenTokenIsConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN); + AuthenticationDetailsSource authenticationDetailsSource = Mockito + .mock(AuthenticationDetailsSource.class); + this.converter.setAuthenticationDetailsSource(authenticationDetailsSource); + + Authentication authentication = this.converter.convert(request); + + verify(authenticationDetailsSource).buildDetails(any()); + assertThat(authentication).isNotNull(); + } + + @Test + public void convertWhenFormParameterIsPresentAndAllowFormEncodedBodyParameterThenConverted() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod(HttpMethod.POST.name()); + request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); + request.addParameter("access_token", BEARER_TOKEN); + this.converter.setAllowFormEncodedBodyParameter(true); + + assertThat(this.converter.convert(request)).isNotNull(); + } + +} diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index cc7477684f..465b5261c6 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -293,6 +293,16 @@ public class BearerTokenAuthenticationFilterTests { // @formatter:on } + @Test + public void setConverterWhenNullThenThrowsException() { + // @formatter:off + BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager); + assertThatIllegalArgumentException() + .isThrownBy(() -> filter.setAuthenticationConverter(null)) + .withMessageContaining("authenticationConverter cannot be null"); + // @formatter:on + } + @Test public void constructorWhenNullAuthenticationManagerThenThrowsException() { // @formatter:off From 30577bd291781d34b4550404872cfba657278edc Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 11 Apr 2025 15:36:23 +0300 Subject: [PATCH 295/504] Add Additional Tests To BearerTokenAuthenticationFilterTests Issue gh-14750 Signed-off-by: Max Batischev --- .../BearerTokenAuthenticationFilterTests.java | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index 465b5261c6..b64a29f762 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -52,6 +52,7 @@ import org.springframework.security.oauth2.server.resource.authentication.Bearer import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository; @@ -74,6 +75,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) public class BearerTokenAuthenticationFilterTests { + private static final String TEST_TOKEN = "token"; + @Mock AuthenticationEntryPoint authenticationEntryPoint; @@ -92,6 +95,9 @@ public class BearerTokenAuthenticationFilterTests { @Mock AuthenticationDetailsSource authenticationDetailsSource; + @Mock + AuthenticationConverter authenticationConverter; + MockHttpServletRequest request; MockHttpServletResponse response; @@ -321,6 +327,171 @@ public class BearerTokenAuthenticationFilterTests { // @formatter:on } + @Test + public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates() throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) + .isNotNull(); + } + + @Test + public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves() throws ServletException, IOException { + SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("test", "password"); + given(this.authenticationManager.authenticate(any())).willReturn(expectedAuthentication); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.setSecurityContextRepository(securityContextRepository); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + ArgumentCaptor contextArg = ArgumentCaptor.forClass(SecurityContext.class); + verify(securityContextRepository).saveContext(contextArg.capture(), eq(this.request), eq(this.response)); + assertThat(contextArg.getValue().getAuthentication().getName()).isEqualTo(expectedAuthentication.getName()); + } + + @Test + public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates() throws Exception { + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManagerResolver)); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManagerResolver.resolve(any())).willReturn(this.authenticationManager); + + filter.doFilter(this.request, this.response, this.filterChain); + + ArgumentCaptor captor = ArgumentCaptor + .forClass(BearerTokenAuthenticationToken.class); + verify(this.authenticationManager).authenticate(captor.capture()); + assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); + assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) + .isNotNull(); + } + + @Test + public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate() + throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)).willReturn(null); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + verifyNoMoreInteractions(this.authenticationManager); + } + + @Test + public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, HttpStatus.BAD_REQUEST, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.doFilter(this.request, this.response, this.filterChain); + + verifyNoMoreInteractions(this.authenticationManager); + verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); + } + + @Test + public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); + } + + @Test + public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError() + throws ServletException, IOException { + BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, + "description", "uri"); + OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.setAuthenticationFailureHandler(this.authenticationFailureHandler); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception); + } + + @Test + public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows() { + AuthenticationServiceException exception = new AuthenticationServiceException("message"); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any())).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + + assertThatExceptionOfType(AuthenticationServiceException.class) + .isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain)); + } + + @Test + public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses() + throws ServletException, IOException { + AuthenticationException exception = new InvalidBearerTokenException("message"); + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + given(this.authenticationManager.authenticate(any())).willThrow(exception); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + AuthenticationEntryPoint entrypoint = mock(AuthenticationEntryPoint.class); + filter.setAuthenticationEntryPoint(entrypoint); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(entrypoint).commence(any(), any(), any(InvalidBearerTokenException.class)); + } + + @Test + public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses() + throws ServletException, IOException { + given(this.authenticationConverter.convert(this.request)) + .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); + BearerTokenAuthenticationFilter filter = addMocksWithConverter( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class); + given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl()); + filter.setSecurityContextHolderStrategy(strategy); + + filter.doFilter(this.request, this.response, this.filterChain); + + verify(strategy).setContext(any()); + } + private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) { filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); filter.setBearerTokenResolver(this.bearerTokenResolver); @@ -335,4 +506,10 @@ public class BearerTokenAuthenticationFilterTests { verifyNoMoreInteractions(this.authenticationManager); } + private BearerTokenAuthenticationFilter addMocksWithConverter(BearerTokenAuthenticationFilter filter) { + filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); + filter.setAuthenticationConverter(this.authenticationConverter); + return filter; + } + } From eaab42a73c988523120441678d1f74d256465c9a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 4 Jun 2025 13:35:31 -0600 Subject: [PATCH 296/504] Polish BearerTokenAuthenticationConverter Support - Moved to BearerTokenAuthenticationFilter constructor to align with AuthenticationFilter - Undeprecated BearerTokenResolver to reduce number of migration scenarios - Updated to 7.0 schema - Added migration docs Issue gh-14750 --- .../OAuth2ResourceServerConfigurer.java | 37 ++-- ...th2ResourceServerBeanDefinitionParser.java | 12 +- .../security/config/spring-security-6.5.rnc | 3 - .../security/config/spring-security-6.5.xsd | 6 - .../security/config/spring-security-7.0.rnc | 3 + .../security/config/spring-security-7.0.xsd | 6 + .../OAuth2ResourceServerConfigurerTests.java | 16 +- .../ROOT/pages/migration/servlet/oauth2.adoc | 55 +++++ .../servlet/appendix/namespace/http.adoc | 6 +- .../resource/web/BearerTokenResolver.java | 5 +- .../BearerTokenAuthenticationConverter.java | 127 +---------- .../BearerTokenAuthenticationFilter.java | 92 +++++--- ...arerTokenAuthenticationConverterTests.java | 14 +- .../BearerTokenAuthenticationFilterTests.java | 197 ++---------------- 14 files changed, 203 insertions(+), 376 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index 8d44dfdcb5..c4b976bc99 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -23,8 +23,6 @@ import java.util.Map; import java.util.function.Supplier; import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.core.convert.converter.Converter; @@ -44,7 +42,6 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; -import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; @@ -69,7 +66,6 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; import org.springframework.web.accept.ContentNegotiationStrategy; import org.springframework.web.accept.HeaderContentNegotiationStrategy; @@ -200,13 +196,9 @@ public final class OAuth2ResourceServerConfigurer bearerTokenResolver(BearerTokenResolver bearerTokenResolver) { Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); - this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); + this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver); return this; } @@ -214,7 +206,7 @@ public final class OAuth2ResourceServerConfigurer authenticationConverter(AuthenticationConverter authenticationConverter) { Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); @@ -299,10 +291,9 @@ public final class OAuth2ResourceServerConfigurer authenticationManager; } - BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver); AuthenticationConverter converter = getAuthenticationConverter(); this.requestMatcher.setAuthenticationConverter(converter); - filter.setAuthenticationConverter(converter); + BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver, converter); filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); filter = postProcess(filter); @@ -394,7 +385,7 @@ public final class OAuth2ResourceServerConfigurer 0) { BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); - this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); + this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver); } else { this.authenticationConverter = new BearerTokenAuthenticationConverter(); @@ -404,7 +395,7 @@ public final class OAuth2ResourceServerConfigurer - - - Reference to a AuthenticationConverter - - - diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc index 15d15b191b..bbf8622dfe 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -650,6 +650,9 @@ oauth2-resource-server.attlist &= oauth2-resource-server.attlist &= ## Reference to a AuthenticationEntryPoint attribute entry-point-ref {xsd:token}? +oauth2-resource-server.attlist &= + ## Reference to a AuthenticationConverter + attribute authentication-converter-ref {xsd:token}? jwt = ## Configures JWT authentication diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 34556b5549..2e3d6cf275 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -1999,6 +1999,12 @@ + + + Reference to a AuthenticationConverter + + + diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 5c655f5afd..23dde67586 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -2571,16 +2571,20 @@ public class OAuth2ResourceServerConfigurerTests { @Bean AuthenticationConverter authenticationConverterOne() { - BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); - converter.setAllowUriQueryParameter(true); - return converter; + DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver(); + resolver.setAllowUriQueryParameter(true); + BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter(); + authenticationConverter.setBearerTokenResolver(resolver); + return authenticationConverter; } @Bean AuthenticationConverter authenticationConverterTwo() { - BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); - converter.setAllowUriQueryParameter(true); - return converter; + DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver(); + resolver.setAllowUriQueryParameter(true); + BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter(); + authenticationConverter.setBearerTokenResolver(resolver); + return authenticationConverter; } } diff --git a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc index 6cdb9043dd..293abadddb 100644 --- a/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc +++ b/docs/modules/ROOT/pages/migration/servlet/oauth2.adoc @@ -115,3 +115,58 @@ fun authenticationConverter(val registrations: RelyingPartyRegistrationRepositor ====== If you must continue using `Saml2AuthenticationTokenConverter`, `OpenSaml4AuthenticationTokenConverter`, or `OpenSaml5AuthenticationTokenConverter` to process GET requests, you can call `setShouldConvertGetRequests` to `true.` + +== Provide an AuthenticationConverter to BearerTokenAuthenticationFilter + +In Spring Security 7, `BearerTokenAuthenticationFilter#setBearerTokenResolver` and `#setAuthenticaionDetailsSource` are deprecated in favor of configuring those on `BearerTokenAuthenticationConverter`. + +The `oauth2ResourceServer` DSL addresses most use cases and you need to nothing. + +If you are setting a `BearerTokenResolver` or `AuthenticationDetailsSource` directly on `BearerTokenAuthenticationFilter` similar to the following: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(authenticationManager); +filter.setBearerTokenResolver(myBearerTokenResolver); +filter.setAuthenticationDetailsSource(myAuthenticationDetailsSource); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val filter = BearerTokenAuthenticationFilter(authenticationManager) +filter.setBearerTokenResolver(myBearerTokenResolver) +filter.setAuthenticationDetailsSource(myAuthenticationDetailsSource) +---- +====== + +you are encouraged to use `BearerTokenAuthenticationConverter` to specify both: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +BearerTokenAuthenticationConverter authenticationConverter = + new BearerTokenAuthenticationConverter(); +authenticationConverter.setBearerTokenResolver(myBearerTokenResolver); +authenticationConverter.setAuthenticationDetailsSource(myAuthenticationDetailsSource); +BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(authenticationManager, authenicationConverter); +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +val authenticationConverter = BearerTokenAuthenticationConverter() +authenticationConverter.setBearerTokenResolver(myBearerTokenResolver) +authenticationConverter.setAuthenticationDetailsSource(myAuthenticationDetailsSource) +val filter = BearerTokenAuthenticationFilter(authenticationManager, authenticationConverter) +---- +====== diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index d5438e0f43..8979d5ad29 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -1266,7 +1266,8 @@ Reference to an `AuthenticationManagerResolver` which will resolve the `Authenti [[nsa-oauth2-resource-server-bearer-token-resolver-ref]] * **bearer-token-resolver-ref** -Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request +Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request. +This cannot be used in conjunction with `authentication-converter-ref` [[nsa-oauth2-resource-server-entry-point-ref]] * **entry-point-ref** @@ -1274,7 +1275,8 @@ Reference to a `AuthenticationEntryPoint` which will handle unauthorized request [[nsa-oauth2-resource-server-authentication-converter-ref]] * **authentication-converter-ref** -Reference to a `AuthenticationConverter` which convert request to authentication +Reference to a `AuthenticationConverter` which convert request to authentication. +This cannot be used in conjunction with `bearer-token-resolver-ref` [[nsa-jwt]] == diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java index 0fd023c5f6..7abd174630 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/BearerTokenResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,10 +29,7 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; * @since 5.1 * @see RFC 6750 * Section 2: Authenticated Requests - * @deprecated Use - * {@link org.springframework.security.web.authentication.AuthenticationConverter} instead */ -@Deprecated @FunctionalInterface public interface BearerTokenResolver { diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java index 211a49bf21..9f7e91a40a 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverter.java @@ -16,20 +16,13 @@ package org.springframework.security.oauth2.server.resource.web.authentication; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import jakarta.servlet.http.HttpServletRequest; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.server.resource.BearerTokenError; -import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; +import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.util.Assert; @@ -40,131 +33,29 @@ import org.springframework.util.StringUtils; * {@link BearerTokenAuthenticationToken} * * @author Max Batischev - * @since 6.5 + * @author Josh Cummings + * @since 7.0 */ public final class BearerTokenAuthenticationConverter implements AuthenticationConverter { private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); - private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+=*)$", - Pattern.CASE_INSENSITIVE); - - private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token"; - - private boolean allowFormEncodedBodyParameter = false; - - private boolean allowUriQueryParameter = false; - - private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; + private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver(); @Override public Authentication convert(HttpServletRequest request) { - String token = resolveToken(request); + String token = this.bearerTokenResolver.resolve(request); if (StringUtils.hasText(token)) { BearerTokenAuthenticationToken authenticationToken = new BearerTokenAuthenticationToken(token); authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request)); - return authenticationToken; } return null; } - private String resolveToken(HttpServletRequest request) { - final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); - final String parameterToken = isParameterTokenSupportedForRequest(request) - ? resolveFromRequestParameters(request) : null; - if (authorizationHeaderToken != null) { - if (parameterToken != null) { - final BearerTokenError error = BearerTokenErrors - .invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } - return authorizationHeaderToken; - } - if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { - return parameterToken; - } - return null; - } - - private String resolveFromAuthorizationHeader(HttpServletRequest request) { - String authorization = request.getHeader(this.bearerTokenHeaderName); - if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { - return null; - } - Matcher matcher = authorizationPattern.matcher(authorization); - if (!matcher.matches()) { - BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); - throw new OAuth2AuthenticationException(error); - } - return matcher.group("token"); - } - - private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) { - return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request) - && !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request))); - } - - private static String resolveFromRequestParameters(HttpServletRequest request) { - String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME); - if (values == null || values.length == 0) { - return null; - } - if (values.length == 1) { - return values[0]; - } - BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } - - private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) { - return isFormEncodedRequest(request) || isGetRequest(request); - } - - private boolean isGetRequest(HttpServletRequest request) { - return HttpMethod.GET.name().equals(request.getMethod()); - } - - private boolean isFormEncodedRequest(HttpServletRequest request) { - return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()); - } - - private static boolean hasAccessTokenInQueryString(HttpServletRequest request) { - return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME); - } - - /** - * Set if transport of access token using URI query parameter is supported. Defaults - * to {@code false}. - * - * The spec recommends against using this mechanism for sending bearer tokens, and - * even goes as far as stating that it was only included for completeness. - * @param allowUriQueryParameter if the URI query parameter is supported - */ - public void setAllowUriQueryParameter(boolean allowUriQueryParameter) { - this.allowUriQueryParameter = allowUriQueryParameter; - } - - /** - * Set this value to configure what header is checked when resolving a Bearer Token. - * This value is defaulted to {@link HttpHeaders#AUTHORIZATION}. - * - * This allows other headers to be used as the Bearer Token source such as - * {@link HttpHeaders#PROXY_AUTHORIZATION} - * @param bearerTokenHeaderName the header to check when retrieving the Bearer Token. - */ - public void setBearerTokenHeaderName(String bearerTokenHeaderName) { - this.bearerTokenHeaderName = bearerTokenHeaderName; - } - - /** - * Set if transport of access token using form-encoded body parameter is supported. - * Defaults to {@code false}. - * @param allowFormEncodedBodyParameter if the form-encoded body parameter is - * supported - */ - public void setAllowFormEncodedBodyParameter(boolean allowFormEncodedBodyParameter) { - this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter; + public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) { + Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); + this.bearerTokenResolver = bearerTokenResolver; } /** diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java index 5aa819f6be..6a5f5c4869 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java @@ -40,6 +40,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider; +import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint; import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; @@ -76,6 +77,8 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { private final AuthenticationManagerResolver authenticationManagerResolver; + private final AuthenticationConverter authenticationConverter; + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder .getContextHolderStrategy(); @@ -84,20 +87,15 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { private AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler( (request, response, exception) -> this.authenticationEntryPoint.commence(request, response, exception)); - private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); - private SecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository(); - private AuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter(); - /** * Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s) * @param authenticationManagerResolver */ public BearerTokenAuthenticationFilter( AuthenticationManagerResolver authenticationManagerResolver) { - Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null"); - this.authenticationManagerResolver = authenticationManagerResolver; + this(authenticationManagerResolver, new BearerTokenAuthenticationConverter()); } /** @@ -105,8 +103,43 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { * @param authenticationManager */ public BearerTokenAuthenticationFilter(AuthenticationManager authenticationManager) { + this(authenticationManager, new BearerTokenAuthenticationConverter()); + } + + /** + * Construct this filter using the provided parameters + * @param authenticationManager the {@link AuthenticationManager} to use + * @param authenticationConverter the {@link AuthenticationConverter} to use + * @since 7.0 + * @see JwtAuthenticationProvider + * @see OpaqueTokenAuthenticationProvider + * @see BearerTokenAuthenticationConverter + */ + public BearerTokenAuthenticationFilter(AuthenticationManager authenticationManager, + AuthenticationConverter authenticationConverter) { Assert.notNull(authenticationManager, "authenticationManager cannot be null"); - this.authenticationManagerResolver = (request) -> authenticationManager; + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + this.authenticationManagerResolver = (authentication) -> authenticationManager; + this.authenticationConverter = authenticationConverter; + } + + /** + * Construct this filter using the provided parameters + * @param authenticationManagerResolver the {@link AuthenticationManagerResolver} to + * use + * @param authenticationConverter the {@link AuthenticationConverter} to use + * @since 7.0 + * @see JwtAuthenticationProvider + * @see OpaqueTokenAuthenticationProvider + * @see BearerTokenAuthenticationConverter + */ + public BearerTokenAuthenticationFilter( + AuthenticationManagerResolver authenticationManagerResolver, + AuthenticationConverter authenticationConverter) { + Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null"); + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + this.authenticationManagerResolver = authenticationManagerResolver; + this.authenticationConverter = authenticationConverter; } /** @@ -190,17 +223,20 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { * Set the {@link BearerTokenResolver} to use. Defaults to * {@link DefaultBearerTokenResolver}. * @param bearerTokenResolver the {@code BearerTokenResolver} to use + * @deprecated Please provide an {@link AuthenticationConverter} in the constructor + * instead + * @see BearerTokenAuthenticationConverter */ + @Deprecated public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) { Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); - this.authenticationConverter = (request) -> { - String token = bearerTokenResolver.resolve(request); - if (!StringUtils.hasText(token)) { - this.logger.trace("Did not process request since did not find bearer token"); - return null; - } - return new BearerTokenAuthenticationToken(token); - }; + if (this.authenticationConverter instanceof BearerTokenAuthenticationConverter converter) { + converter.setBearerTokenResolver(bearerTokenResolver); + } + else { + throw new IllegalArgumentException( + "You cannot both specify an AuthenticationConverter and a BearerTokenResolver."); + } } /** @@ -227,13 +263,24 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { /** * Set the {@link AuthenticationDetailsSource} to use. Defaults to * {@link WebAuthenticationDetailsSource}. - * @param authenticationDetailsSource the {@code AuthenticationConverter} to use + * @param authenticationDetailsSource the {@code AuthenticationDetailsSource} to use * @since 5.5 + * @deprecated Please provide an {@link AuthenticationConverter} in the constructor + * and set the {@link AuthenticationDetailsSource} there instead. For example, you can + * use {@link BearerTokenAuthenticationConverter#setAuthenticationDetailsSource} + * @see BearerTokenAuthenticationConverter */ + @Deprecated public void setAuthenticationDetailsSource( AuthenticationDetailsSource authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null"); - this.authenticationDetailsSource = authenticationDetailsSource; + if (this.authenticationConverter instanceof BearerTokenAuthenticationConverter converter) { + converter.setAuthenticationDetailsSource(authenticationDetailsSource); + } + else { + throw new IllegalArgumentException( + "You cannot specify both an AuthenticationConverter and an AuthenticationDetailsSource"); + } } private static boolean isDPoPBoundAccessToken(Authentication authentication) { @@ -249,15 +296,4 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { return StringUtils.hasText(jwkThumbprintClaim); } - /** - * Set the {@link AuthenticationConverter} to use. Defaults to - * {@link BearerTokenAuthenticationConverter}. - * @param authenticationConverter the {@code AuthenticationConverter} to use - * @since 6.5 - */ - public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { - Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); - this.authenticationConverter = authenticationConverter; - } - } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java index a5655a0c11..061f3b2232 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationConverterTests.java @@ -27,6 +27,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -46,8 +47,14 @@ public class BearerTokenAuthenticationConverterTests { private static final String BEARER_TOKEN = "test_bearer_token"; + private final DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver(); + private final BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter(); + { + this.converter.setBearerTokenResolver(this.resolver); + } + @Test public void convertWhenAuthorizationHeaderIsPresentThenTokenIsConverted() { MockHttpServletRequest request = new MockHttpServletRequest(); @@ -64,7 +71,7 @@ public class BearerTokenAuthenticationConverterTests { request.setMethod(HttpMethod.GET.name()); request.addParameter("access_token", BEARER_TOKEN); - this.converter.setAllowUriQueryParameter(true); + this.resolver.setAllowUriQueryParameter(true); Authentication authentication = this.converter.convert(request); assertThat(authentication).isNotNull(); @@ -86,6 +93,7 @@ public class BearerTokenAuthenticationConverterTests { request.setMethod(HttpMethod.GET.name()); request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN); + this.resolver.setAllowUriQueryParameter(true); assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request)) .withMessageContaining("Found multiple bearer tokens in the request"); } @@ -95,7 +103,7 @@ public class BearerTokenAuthenticationConverterTests { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader(X_AUTH_TOKEN_HEADER, "Bearer " + TEST_X_AUTH_TOKEN); - this.converter.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER); + this.resolver.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER); Authentication authentication = this.converter.convert(request); assertThat(authentication).isNotNull(); @@ -140,7 +148,7 @@ public class BearerTokenAuthenticationConverterTests { request.setMethod(HttpMethod.POST.name()); request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); request.addParameter("access_token", BEARER_TOKEN); - this.converter.setAllowFormEncodedBodyParameter(true); + this.resolver.setAllowFormEncodedBodyParameter(true); assertThat(this.converter.convert(request)).isNotNull(); } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index b64a29f762..67131e21b6 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -75,8 +75,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @ExtendWith(MockitoExtension.class) public class BearerTokenAuthenticationFilterTests { - private static final String TEST_TOKEN = "token"; - @Mock AuthenticationEntryPoint authenticationEntryPoint; @@ -95,9 +93,6 @@ public class BearerTokenAuthenticationFilterTests { @Mock AuthenticationDetailsSource authenticationDetailsSource; - @Mock - AuthenticationConverter authenticationConverter; - MockHttpServletRequest request; MockHttpServletResponse response; @@ -269,6 +264,24 @@ public class BearerTokenAuthenticationFilterTests { assertThat(error.getDescription()).isEqualTo("Invalid bearer token"); } + @Test + public void doFilterWhenSetAuthenticationConverterAndAuthenticationDetailsSourceThenIllegalArgument( + @Mock AuthenticationConverter authenticationConverter) { + BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager, + authenticationConverter); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> filter.setAuthenticationDetailsSource(this.authenticationDetailsSource)); + } + + @Test + public void doFilterWhenSetBearerTokenResolverAndAuthenticationConverterThenIllegalArgument( + @Mock AuthenticationConverter authenticationConverter) { + BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager, + authenticationConverter); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> filter.setBearerTokenResolver(this.bearerTokenResolver)); + } + @Test public void setAuthenticationEntryPointWhenNullThenThrowsException() { BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager); @@ -302,9 +315,8 @@ public class BearerTokenAuthenticationFilterTests { @Test public void setConverterWhenNullThenThrowsException() { // @formatter:off - BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager); assertThatIllegalArgumentException() - .isThrownBy(() -> filter.setAuthenticationConverter(null)) + .isThrownBy(() -> new BearerTokenAuthenticationFilter(this.authenticationManager, null)) .withMessageContaining("authenticationConverter cannot be null"); // @formatter:on } @@ -327,171 +339,6 @@ public class BearerTokenAuthenticationFilterTests { // @formatter:on } - @Test - public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates() throws ServletException, IOException { - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - - filter.doFilter(this.request, this.response, this.filterChain); - - ArgumentCaptor captor = ArgumentCaptor - .forClass(BearerTokenAuthenticationToken.class); - verify(this.authenticationManager).authenticate(captor.capture()); - assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); - assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) - .isNotNull(); - } - - @Test - public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves() throws ServletException, IOException { - SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("test", "password"); - given(this.authenticationManager.authenticate(any())).willReturn(expectedAuthentication); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - filter.setSecurityContextRepository(securityContextRepository); - - filter.doFilter(this.request, this.response, this.filterChain); - - ArgumentCaptor captor = ArgumentCaptor - .forClass(BearerTokenAuthenticationToken.class); - verify(this.authenticationManager).authenticate(captor.capture()); - assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); - ArgumentCaptor contextArg = ArgumentCaptor.forClass(SecurityContext.class); - verify(securityContextRepository).saveContext(contextArg.capture(), eq(this.request), eq(this.response)); - assertThat(contextArg.getValue().getAuthentication().getName()).isEqualTo(expectedAuthentication.getName()); - } - - @Test - public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates() throws Exception { - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManagerResolver)); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - given(this.authenticationManagerResolver.resolve(any())).willReturn(this.authenticationManager); - - filter.doFilter(this.request, this.response, this.filterChain); - - ArgumentCaptor captor = ArgumentCaptor - .forClass(BearerTokenAuthenticationToken.class); - verify(this.authenticationManager).authenticate(captor.capture()); - assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN); - assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME)) - .isNotNull(); - } - - @Test - public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate() - throws ServletException, IOException { - given(this.authenticationConverter.convert(this.request)).willReturn(null); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - - filter.doFilter(this.request, this.response, this.filterChain); - - verifyNoMoreInteractions(this.authenticationManager); - } - - @Test - public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError() - throws ServletException, IOException { - BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, HttpStatus.BAD_REQUEST, - "description", "uri"); - OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); - given(this.authenticationConverter.convert(this.request)).willThrow(exception); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - filter.doFilter(this.request, this.response, this.filterChain); - - verifyNoMoreInteractions(this.authenticationManager); - verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); - } - - @Test - public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError() - throws ServletException, IOException { - BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, - "description", "uri"); - OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - - filter.doFilter(this.request, this.response, this.filterChain); - - verify(this.authenticationEntryPoint).commence(this.request, this.response, exception); - } - - @Test - public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError() - throws ServletException, IOException { - BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED, - "description", "uri"); - OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - filter.setAuthenticationFailureHandler(this.authenticationFailureHandler); - - filter.doFilter(this.request, this.response, this.filterChain); - - verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception); - } - - @Test - public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows() { - AuthenticationServiceException exception = new AuthenticationServiceException("message"); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - given(this.authenticationManager.authenticate(any())).willThrow(exception); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - - assertThatExceptionOfType(AuthenticationServiceException.class) - .isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain)); - } - - @Test - public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses() - throws ServletException, IOException { - AuthenticationException exception = new InvalidBearerTokenException("message"); - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - given(this.authenticationManager.authenticate(any())).willThrow(exception); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - AuthenticationEntryPoint entrypoint = mock(AuthenticationEntryPoint.class); - filter.setAuthenticationEntryPoint(entrypoint); - - filter.doFilter(this.request, this.response, this.filterChain); - - verify(entrypoint).commence(any(), any(), any(InvalidBearerTokenException.class)); - } - - @Test - public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses() - throws ServletException, IOException { - given(this.authenticationConverter.convert(this.request)) - .willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN)); - BearerTokenAuthenticationFilter filter = addMocksWithConverter( - new BearerTokenAuthenticationFilter(this.authenticationManager)); - SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class); - given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl()); - filter.setSecurityContextHolderStrategy(strategy); - - filter.doFilter(this.request, this.response, this.filterChain); - - verify(strategy).setContext(any()); - } - private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) { filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); filter.setBearerTokenResolver(this.bearerTokenResolver); @@ -506,10 +353,4 @@ public class BearerTokenAuthenticationFilterTests { verifyNoMoreInteractions(this.authenticationManager); } - private BearerTokenAuthenticationFilter addMocksWithConverter(BearerTokenAuthenticationFilter filter) { - filter.setAuthenticationEntryPoint(this.authenticationEntryPoint); - filter.setAuthenticationConverter(this.authenticationConverter); - return filter; - } - } From a0c5504ecaad467f6f1fca2c99025ff825eb729c Mon Sep 17 00:00:00 2001 From: damable-nuvolex Date: Mon, 2 Jun 2025 14:03:46 -0500 Subject: [PATCH 297/504] Fix inconsistent constructor declaration Closes gh-16325 Signed-off-by: damable-nuvolex --- ...iveAuthorizationManagerMethodSecurityConfiguration.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java index 7373d7b8c4..9ee76c3333 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,10 +83,11 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor; - @Autowired(required = false) - ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler, + ReactiveAuthorizationManagerMethodSecurityConfiguration( + ObjectProvider expressionHandlers, ObjectProvider>> preAuthorizePostProcessor, ObjectProvider>> postAuthorizePostProcessor) { + MethodSecurityExpressionHandler expressionHandler = expressionHandlers.getIfUnique(); if (expressionHandler != null) { this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler); this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler); From 3b12e758d34f7074a89fe9342f1b2385f69f99b7 Mon Sep 17 00:00:00 2001 From: damable-nuvolex Date: Mon, 2 Jun 2025 14:03:46 -0500 Subject: [PATCH 298/504] Fix inconsistent constructor declaration Closes gh-16325 Signed-off-by: damable-nuvolex --- ...iveAuthorizationManagerMethodSecurityConfiguration.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java index 7373d7b8c4..9ee76c3333 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,10 +83,11 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor; - @Autowired(required = false) - ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler, + ReactiveAuthorizationManagerMethodSecurityConfiguration( + ObjectProvider expressionHandlers, ObjectProvider>> preAuthorizePostProcessor, ObjectProvider>> postAuthorizePostProcessor) { + MethodSecurityExpressionHandler expressionHandler = expressionHandlers.getIfUnique(); if (expressionHandler != null) { this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler); this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler); From dab989d7c31c5f588e27e07110c05a020d4a2880 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:23:57 -0400 Subject: [PATCH 299/504] Fix NPE with DPoP tokenAuthenticationManager Closes gh-17172 --- .../DPoPAuthenticationConfigurer.java | 23 ++++++++++++++++++- .../OAuth2ResourceServerConfigurer.java | 4 ++++ .../OAuth2ResourceServerConfigurerTests.java | 5 +++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java index cee89e0427..771d6c6e99 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurer.java @@ -29,6 +29,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.Authentication; @@ -51,6 +52,9 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; /** * An {@link AbstractHttpConfigurer} for OAuth 2.0 Demonstrating Proof of Possession @@ -76,7 +80,7 @@ final class DPoPAuthenticationConfigurer> @Override public void configure(B http) { AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); - http.authenticationProvider(new DPoPAuthenticationProvider(authenticationManager)); + http.authenticationProvider(new DPoPAuthenticationProvider(getTokenAuthenticationManager(http))); AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager, getAuthenticationConverter()); authenticationFilter.setRequestMatcher(getRequestMatcher()); @@ -87,6 +91,23 @@ final class DPoPAuthenticationConfigurer> http.addFilter(authenticationFilter); } + private AuthenticationManager getTokenAuthenticationManager(B http) { + OAuth2ResourceServerConfigurer resourceServerConfigurer = http + .getConfigurer(OAuth2ResourceServerConfigurer.class); + final AuthenticationManagerResolver authenticationManagerResolver = resourceServerConfigurer + .getAuthenticationManagerResolver(); + if (authenticationManagerResolver == null) { + return resourceServerConfigurer.getAuthenticationManager(http); + } + return (authentication) -> { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; + AuthenticationManager authenticationManager = authenticationManagerResolver + .resolve(servletRequestAttributes.getRequest()); + return authenticationManager.authenticate(authentication); + }; + } + private RequestMatcher getRequestMatcher() { if (this.requestMatcher == null) { this.requestMatcher = new DPoPRequestMatcher(); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index e9a425d46d..5add89675f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -363,6 +363,10 @@ public final class OAuth2ResourceServerConfigurer getAuthenticationManagerResolver() { + return this.authenticationManagerResolver; + } + BearerTokenResolver getBearerTokenResolver() { if (this.bearerTokenResolver == null) { if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 6b263c7048..81b0a86498 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -88,6 +88,7 @@ import org.springframework.security.config.annotation.method.configuration.Enabl import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; @@ -2532,7 +2533,9 @@ public class OAuth2ResourceServerConfigurerTests { // @formatter:off http .oauth2ResourceServer() - .authenticationManagerResolver(authenticationManagerResolver); + .authenticationManagerResolver(authenticationManagerResolver) + .and() + .anonymous(AbstractHttpConfigurer::disable); return http.build(); // @formatter:on } From f75ac6c83785a876c0225e3d879f0cf5970c00eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:37:31 +0000 Subject: [PATCH 300/504] Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10 Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10. --- updated-dependencies: - dependency-name: org.apache.maven:maven-resolver-provider dependency-version: 3.9.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9c405db07d..3c0e6be649 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.di org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" -org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.9" +org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-impl = { module = "org.apache.maven.resolver:maven-resolver-impl", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-transport-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "org-apache-maven-resolver" } From 47b6e316065515d60e6adeb0aa4e6986b21ad2ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:40:05 +0000 Subject: [PATCH 301/504] Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10 Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10. --- updated-dependencies: - dependency-name: org.apache.maven:maven-resolver-provider dependency-version: 3.9.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ca108e9b2..80c0944784 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,7 @@ org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.di org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" -org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.9" +org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-impl = { module = "org.apache.maven.resolver:maven-resolver-impl", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-transport-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "org-apache-maven-resolver" } From adca1b31be5569be03b1af3d79b8a82e99a7cb40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:52:18 +0000 Subject: [PATCH 302/504] Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10 Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10. --- updated-dependencies: - dependency-name: org.apache.maven:maven-resolver-provider dependency-version: 3.9.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6a16532177..0109327663 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.di org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" -org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.9" +org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-impl = { module = "org.apache.maven.resolver:maven-resolver-impl", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-transport-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "org-apache-maven-resolver" } From 893d539c188f9af7962c485f0c18f17c21cabb9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:55:31 +0000 Subject: [PATCH 303/504] Bump org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10 Bumps org.apache.maven:maven-resolver-provider from 3.9.9 to 3.9.10. --- updated-dependencies: - dependency-name: org.apache.maven:maven-resolver-provider dependency-version: 3.9.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04b1cfa6b1..ef30917b2b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.di org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" -org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.9" +org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-impl = { module = "org.apache.maven.resolver:maven-resolver-impl", version.ref = "org-apache-maven-resolver" } org-apache-maven-resolver-maven-resolver-transport-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "org-apache-maven-resolver" } From b0f8aa5ea02d9abf1bc7b24e128e260cdbb63774 Mon Sep 17 00:00:00 2001 From: Andrey Litvitski Date: Thu, 5 Jun 2025 17:17:42 +0300 Subject: [PATCH 304/504] Fix to allow multiple AuthenticationFilter instances to process each request Closes gh-17173 Signed-off-by: Andrey Litvitski --- .../authentication/AuthenticationFilter.java | 12 +++++++++++- .../AuthenticationFilterTests.java | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java index e4b752fd39..7a1a363f69 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,6 +64,7 @@ import org.springframework.web.filter.OncePerRequestFilter; * * * @author Sergey Bespalov + * @author Andrey Litvitski * @since 5.2.0 */ public class AuthenticationFilter extends OncePerRequestFilter { @@ -193,6 +194,15 @@ public class AuthenticationFilter extends OncePerRequestFilter { } } + @Override + protected String getAlreadyFilteredAttributeName() { + String name = getFilterName(); + if (name == null) { + name = getClass().getName().concat("-" + System.identityHashCode(this)); + } + return name + ALREADY_FILTERED_SUFFIX; + } + private void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { this.securityContextHolderStrategy.clearContext(); diff --git a/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java index b4ab4411e4..8ad63e28bb 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.security.web.authentication; import jakarta.servlet.FilterChain; +import jakarta.servlet.Servlet; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; @@ -57,6 +58,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; /** * @author Sergey Bespalov + * @author Andrey Litvitski * @since 5.2.0 */ @ExtendWith(MockitoExtension.class) @@ -318,4 +320,18 @@ public class AuthenticationFilterTests { assertThat(securityContextArg.getValue().getAuthentication()).isEqualTo(authentication); } + @Test + public void filterWhenMultipleInChainThenAllFiltered() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); + MockHttpServletResponse response = new MockHttpServletResponse(); + AuthenticationFilter filter1 = new AuthenticationFilter(this.authenticationManager, + this.authenticationConverter); + AuthenticationConverter converter2 = mock(AuthenticationConverter.class); + AuthenticationFilter filter2 = new AuthenticationFilter(this.authenticationManager, converter2); + FilterChain chain = new MockFilterChain(mock(Servlet.class), filter1, filter2); + chain.doFilter(request, response); + verify(this.authenticationConverter).convert(any()); + verify(converter2).convert(any()); + } + } From eaf818414295f9bfc48232069c3b65794cded99a Mon Sep 17 00:00:00 2001 From: Liviu Gheorghe Date: Sun, 3 Mar 2024 22:21:07 +0200 Subject: [PATCH 305/504] Send saml logout response even when validation errors happen Signed-off-by: Liviu Gheorghe --- .../security/saml2/core/Saml2ErrorCodes.java | 26 +++- .../BaseOpenSamlLogoutResponseResolver.java | 25 +++- .../logout/Saml2LogoutRequestFilter.java | 103 ++++++++------- .../logout/Saml2LogoutResponseResolver.java | 14 ++- .../OpenSaml4LogoutResponseResolver.java | 10 ++ .../OpenSaml4LogoutResponseResolverTests.java | 51 +++++++- .../OpenSaml5LogoutResponseResolver.java | 10 ++ .../logout/Saml2LogoutRequestFilterTests.java | 119 ++++++++++++++++-- 8 files changed, 300 insertions(+), 58 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2ErrorCodes.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2ErrorCodes.java index c45824442f..0777488d22 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2ErrorCodes.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/core/Saml2ErrorCodes.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,6 +130,30 @@ public final class Saml2ErrorCodes { */ public static final String INVALID_IN_RESPONSE_TO = "invalid_in_response_to"; + /** + * The RP registration does not have configured a logout request endpoint + * @since 6.3 + */ + public static final String MISSING_LOGOUT_REQUEST_ENDPOINT = "missing_logout_request_endpoint"; + + /** + * The saml response or logout request was delivered via an invalid binding + * @since 6.3 + */ + public static final String INVALID_BINDING = "invalid_binding"; + + /** + * The saml logout request failed validation + * @since 6.3 + */ + public static final String INVALID_LOGOUT_REQUEST = "invalid_logout_request"; + + /** + * The saml logout response could not be generated + * @since 6.3 + */ + public static final String FAILED_TO_GENERATE_LOGOUT_RESPONSE = "failed_to_generate_logout_response"; + private Saml2ErrorCodes() { } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java index 41a44a1856..71f974b816 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java @@ -43,8 +43,11 @@ import org.opensaml.saml.saml2.core.impl.StatusCodeBuilder; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -130,6 +133,16 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes */ @Override public Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication) { + return resolve(request, authentication, StatusCode.SUCCESS); + } + + @Override + public Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication, + Saml2AuthenticationException authenticationException) { + return resolve(request, authentication, getSamlStatus(authenticationException)); + } + + private Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication, String statusCode) { LogoutRequest logoutRequest = this.saml.deserialize(extractSamlRequest(request)); String registrationId = getRegistrationId(authentication); RelyingPartyRegistration registration = this.relyingPartyRegistrationResolver.resolve(request, registrationId); @@ -152,7 +165,7 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes issuer.setValue(entityId); logoutResponse.setIssuer(issuer); StatusCode code = this.statusCodeBuilder.buildObject(); - code.setValue(StatusCode.SUCCESS); + code.setValue(statusCode); Status status = this.statusBuilder.buildObject(); status.setStatusCode(code); logoutResponse.setStatus(status); @@ -224,6 +237,16 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes return this.saml.serialize(logoutResponse).serialize(); } + private String getSamlStatus(Saml2AuthenticationException exception) { + Saml2Error saml2Error = exception.getSaml2Error(); + return switch (saml2Error.getErrorCode()) { + case Saml2ErrorCodes.MISSING_LOGOUT_REQUEST_ENDPOINT, Saml2ErrorCodes.INVALID_BINDING -> + StatusCode.REQUEST_DENIED; + case Saml2ErrorCodes.INVALID_LOGOUT_REQUEST -> StatusCode.REQUESTER; + default -> StatusCode.RESPONDER; + }; + } + static final class LogoutResponseParameters { private final HttpServletRequest request; diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java index 1476f37624..354fb375fc 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java @@ -31,6 +31,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; @@ -112,52 +113,26 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); - Saml2LogoutRequestValidatorParameters parameters; try { - parameters = this.logoutRequestResolver.resolve(request, authentication); + Saml2LogoutRequestValidatorParameters parameters = this.logoutRequestResolver.resolve(request, + authentication); + if (parameters == null) { + chain.doFilter(request, response); + return; + } + + Saml2LogoutResponse logoutResponse = processLogoutRequest(request, response, authentication, parameters); + sendLogoutResponse(request, response, logoutResponse); } catch (Saml2AuthenticationException ex) { - this.logger.trace("Did not process logout request since failed to find requested RelyingPartyRegistration"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } - if (parameters == null) { - chain.doFilter(request, response); - return; - } - RelyingPartyRegistration registration = parameters.getRelyingPartyRegistration(); - if (registration.getSingleLogoutServiceLocation() == null) { - this.logger.trace( - "Did not process logout request since RelyingPartyRegistration has not been configured with a logout request endpoint"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - return; - } + Saml2LogoutResponse errorLogoutResponse = this.logoutResponseResolver.resolve(request, authentication, ex); + if (errorLogoutResponse == null) { + this.logger.trace("Returning error since no error logout response could be generated", ex); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } - Saml2MessageBinding saml2MessageBinding = Saml2MessageBindingUtils.resolveBinding(request); - if (!registration.getSingleLogoutServiceBindings().contains(saml2MessageBinding)) { - this.logger.trace("Did not process logout request since used incorrect binding"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - - Saml2LogoutValidatorResult result = this.logoutRequestValidator.validate(parameters); - if (result.hasErrors()) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, result.getErrors().iterator().next().toString()); - this.logger.debug(LogMessage.format("Failed to validate LogoutRequest: %s", result.getErrors())); - return; - } - this.handler.logout(request, response, authentication); - Saml2LogoutResponse logoutResponse = this.logoutResponseResolver.resolve(request, authentication); - if (logoutResponse == null) { - this.logger.trace("Returning 401 since no logout response generated"); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - return; - } - if (logoutResponse.getBinding() == Saml2MessageBinding.REDIRECT) { - doRedirect(request, response, logoutResponse); - } - else { - doPost(response, logoutResponse); + sendLogoutResponse(request, response, errorLogoutResponse); } } @@ -180,6 +155,50 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { this.securityContextHolderStrategy = securityContextHolderStrategy; } + private Saml2LogoutResponse processLogoutRequest(HttpServletRequest request, HttpServletResponse response, + Authentication authentication, Saml2LogoutRequestValidatorParameters parameters) { + RelyingPartyRegistration registration = parameters.getRelyingPartyRegistration(); + if (registration.getSingleLogoutServiceLocation() == null) { + this.logger.trace( + "Did not process logout request since RelyingPartyRegistration has not been configured with a logout request endpoint"); + throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.MISSING_LOGOUT_REQUEST_ENDPOINT, + "RelyingPartyRegistration has not been configured with a logout request endpoint")); + } + + Saml2MessageBinding saml2MessageBinding = Saml2MessageBindingUtils.resolveBinding(request); + if (!registration.getSingleLogoutServiceBindings().contains(saml2MessageBinding)) { + this.logger.trace("Did not process logout request since used incorrect binding"); + throw new Saml2AuthenticationException( + new Saml2Error(Saml2ErrorCodes.INVALID_BINDING, "Logout request used invalid binding")); + } + + Saml2LogoutValidatorResult result = this.logoutRequestValidator.validate(parameters); + if (result.hasErrors()) { + this.logger.debug(LogMessage.format("Failed to validate LogoutRequest: %s", result.getErrors())); + throw new Saml2AuthenticationException( + new Saml2Error(Saml2ErrorCodes.INVALID_LOGOUT_REQUEST, "Failed to validate the logout request")); + } + + this.handler.logout(request, response, authentication); + Saml2LogoutResponse logoutResponse = this.logoutResponseResolver.resolve(request, authentication); + if (logoutResponse == null) { + this.logger.trace("Returning error since no logout response generated"); + throw new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.FAILED_TO_GENERATE_LOGOUT_RESPONSE, + "Could not generated logout response")); + } + return logoutResponse; + } + + private void sendLogoutResponse(HttpServletRequest request, HttpServletResponse response, + Saml2LogoutResponse logoutResponse) throws IOException { + if (logoutResponse.getBinding() == Saml2MessageBinding.REDIRECT) { + doRedirect(request, response, logoutResponse); + } + else { + doPost(response, logoutResponse); + } + } + private void doRedirect(HttpServletRequest request, HttpServletResponse response, Saml2LogoutResponse logoutResponse) throws IOException { String location = logoutResponse.getResponseLocation(); diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseResolver.java index f722fd55b7..c156ef928c 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutResponseResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.security.saml2.provider.service.web.authentication.l import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -44,4 +45,15 @@ public interface Saml2LogoutResponseResolver { */ Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication); + /** + * Prepare to create, sign, and serialize a SAML 2.0 Error Logout Response. + * @param request the HTTP request + * @param authentication the current user + * @param authenticationException the thrown exception when the logout request was + * processed + * @return a signed and serialized SAML 2.0 Logout Response + */ + Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication, + Saml2AuthenticationException authenticationException); + } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java index 4d70062b3f..c88f945dd8 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java @@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.opensaml.saml.saml2.core.LogoutRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -66,6 +67,15 @@ public final class OpenSaml4LogoutResponseResolver implements Saml2LogoutRespons return this.delegate.resolve(request, authentication); } + /** + * {@inheritDoc} + */ + @Override + public Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication, + Saml2AuthenticationException exception) { + return this.delegate.resolve(request, authentication, exception); + } + /** * Set a {@link Consumer} for modifying the OpenSAML {@link LogoutRequest} * @param parametersConsumer a consumer that accepts an diff --git a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java index eba07f55c5..b8907c5cd7 100644 --- a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java +++ b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,17 +17,26 @@ package org.springframework.security.saml2.provider.service.web.authentication.logout; import java.util.function.Consumer; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opensaml.saml.saml2.core.LogoutRequest; +import org.opensaml.saml.saml2.core.StatusCode; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; +import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver.LogoutResponseParameters; @@ -69,6 +78,27 @@ public class OpenSaml4LogoutResponseResolverTests { verify(parametersConsumer).accept(any()); } + @ParameterizedTest + @MethodSource("provideAuthExceptionAndExpectedSamlStatusCode") + public void resolveWithAuthException(Saml2AuthenticationException exception, String expectedStatusCode) { + OpenSaml4LogoutResponseResolver logoutResponseResolver = new OpenSaml4LogoutResponseResolver( + this.relyingPartyRegistrationResolver); + MockHttpServletRequest request = new MockHttpServletRequest(); + RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration() + .assertingPartyMetadata( + (party) -> party.singleLogoutServiceResponseLocation("https://ap.example.com/logout") + .singleLogoutServiceBinding(Saml2MessageBinding.POST)) + .build(); + Authentication authentication = new TestingAuthenticationToken("user", "password"); + LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration); + request.setParameter(Saml2ParameterNames.SAML_REQUEST, + Saml2Utils.samlEncode(this.saml.serialize(logoutRequest).serialize().getBytes())); + given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration); + Saml2LogoutResponse logoutResponse = logoutResponseResolver.resolve(request, authentication, exception); + assertThat(logoutResponse).isNotNull(); + assertThat(new String(Saml2Utils.samlDecode(logoutResponse.getSamlResponse()))).contains(expectedStatusCode); + } + @Test public void setParametersConsumerWhenNullThenIllegalArgument() { OpenSaml4LogoutRequestResolver logoutRequestResolver = new OpenSaml4LogoutRequestResolver( @@ -77,4 +107,23 @@ public class OpenSaml4LogoutResponseResolverTests { .isThrownBy(() -> logoutRequestResolver.setParametersConsumer(null)); } + private static Stream provideAuthExceptionAndExpectedSamlStatusCode() { + return Stream.of( + Arguments.of( + new Saml2AuthenticationException( + new Saml2Error(Saml2ErrorCodes.MISSING_LOGOUT_REQUEST_ENDPOINT, "")), + StatusCode.REQUEST_DENIED), + Arguments.of(new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_BINDING, "")), + StatusCode.REQUEST_DENIED), + Arguments.of( + new Saml2AuthenticationException(new Saml2Error(Saml2ErrorCodes.INVALID_LOGOUT_REQUEST, "")), + StatusCode.REQUESTER), + Arguments.of( + new Saml2AuthenticationException( + new Saml2Error(Saml2ErrorCodes.FAILED_TO_GENERATE_LOGOUT_RESPONSE, "")), + StatusCode.RESPONDER) + + ); + } + } diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5LogoutResponseResolver.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5LogoutResponseResolver.java index 4d0b917597..36b3fc021f 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5LogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5LogoutResponseResolver.java @@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.opensaml.saml.saml2.core.LogoutRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -66,6 +67,15 @@ public final class OpenSaml5LogoutResponseResolver implements Saml2LogoutRespons return this.delegate.resolve(request, authentication); } + /** + * {@inheritDoc} + */ + @Override + public Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication, + Saml2AuthenticationException exception) { + return this.delegate.resolve(request, authentication, exception); + } + /** * Set a {@link Consumer} for modifying the OpenSAML {@link LogoutRequest} * @param parametersConsumer a consumer that accepts an diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java index 6b6fcea452..1d6e151eac 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; @@ -40,6 +41,7 @@ import org.springframework.security.web.authentication.logout.LogoutHandler; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.mock; import static org.mockito.Mockito.verify; @@ -117,12 +119,7 @@ public class Saml2LogoutRequestFilterTests { verify(this.logoutRequestValidator).validate(any()); verify(this.logoutHandler).logout(any(), any(), any()); verify(this.logoutResponseResolver).resolve(any(), any()); - String content = response.getContentAsString(); - assertThat(content).contains(Saml2ParameterNames.SAML_RESPONSE); - assertThat(content).contains(registration.getAssertingPartyDetails().getSingleLogoutServiceResponseLocation()); - assertThat(content).contains( - " Date: Tue, 10 Jun 2025 10:46:23 -0500 Subject: [PATCH 315/504] Explicit Permissions for codeql.yml --- .github/workflows/codeql.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 60b01f76f1..dabe0665f0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -7,7 +7,11 @@ on: schedule: # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule - cron: '0 5 * * *' - +permissions: read-all jobs: codeql-analysis-call: + permissions: + actions: read + contents: read + security-events: write uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1 From 36c7b91fb95de1c5e22184a3b259acbf8006e84f Mon Sep 17 00:00:00 2001 From: Christian Schuster Date: Mon, 6 Jun 2022 19:09:42 +0200 Subject: [PATCH 316/504] SAML 2.0 Single Logout Uses Saml2AuthenticationInfo This allows SLO to be triggered without the authentication principal needing to implement a given interface. Issue gh-10820 --- .../saml2/Saml2LogoutConfigurer.java | 7 +- .../http/Saml2LogoutBeanDefinitionParser.java | 7 +- .../Saml2AuthenticatedPrincipal.java | 4 +- .../Saml2AuthenticationInfo.java | 78 +++++++++++++++++++ .../BaseOpenSamlLogoutRequestResolver.java | 17 ++-- ...outRequestValidatorParametersResolver.java | 10 +-- .../BaseOpenSamlLogoutResponseResolver.java | 11 +-- .../logout/Saml2LogoutRequestFilter.java | 10 +-- ...outRequestValidatorParametersResolver.java | 10 +-- 9 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java index e69f8c825b..f8303a81b9 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java @@ -33,7 +33,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolderStrategy; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator; @@ -531,10 +531,7 @@ public final class Saml2LogoutConfigurer> @Override public boolean matches(HttpServletRequest request) { Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (authentication == null) { - return false; - } - return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal; + return Saml2AuthenticationInfo.fromAuthentication(authentication) != null; } } diff --git a/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java index bef7a69d19..dfeed0d981 100644 --- a/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java @@ -31,7 +31,7 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter; import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter; @@ -236,10 +236,7 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser { @Override public boolean matches(HttpServletRequest request) { Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (authentication == null) { - return false; - } - return authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal; + return Saml2AuthenticationInfo.fromAuthentication(authentication) != null; } public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java index 205c5f8941..69eb9d7628 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java @@ -31,7 +31,7 @@ import org.springframework.util.CollectionUtils; * @author Clement Stoquart * @since 5.2.2 */ -public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal { +public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal, Saml2AuthenticationInfo { /** * Get the first value of Saml2 token attribute by name @@ -72,10 +72,12 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal { * @return the {@link RelyingPartyRegistration} identifier * @since 5.6 */ + @Override default String getRelyingPartyRegistrationId() { return null; } + @Override default List getSessionIndexes() { return Collections.emptyList(); } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java new file mode 100644 index 0000000000..309e2a909b --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.authentication; + +import java.util.List; + +import org.opensaml.saml.saml2.core.SessionIndex; + +import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; + +/** + * Additional SAML 2.0 authentication information + * + *

+ * SAML 2.0 Single Logout requires that the {@link Authentication#getPrincipal() + * authenticated principal} or the {@link Authentication} itself implements this + * interface. + * + * @author Christian Schuster + */ +public interface Saml2AuthenticationInfo { + + /** + * Get the {@link RelyingPartyRegistration} identifier + * @return the {@link RelyingPartyRegistration} identifier + */ + String getRelyingPartyRegistrationId(); + + /** + * Get the {@link SessionIndex} values of the authenticated principal + * @return the {@link SessionIndex} values of the authenticated principal + */ + List getSessionIndexes(); + + /** + * Try to obtain a {@link Saml2AuthenticationInfo} instance from an + * {@link Authentication} + * + *

+ * The result is either the {@link Authentication#getPrincipal() authenticated + * principal}, the {@link Authentication} itself, or {@code null}. + * + *

+ * Returning {@code null} indicates that the given {@link Authentication} does not + * represent a SAML 2.0 authentication. + * @param authentication the {@link Authentication} + * @return the {@link Saml2AuthenticationInfo} or {@code null} if unavailable + */ + static Saml2AuthenticationInfo fromAuthentication(Authentication authentication) { + if (authentication == null) { + return null; + } + Object principal = authentication.getPrincipal(); + if (principal instanceof Saml2AuthenticationInfo) { + return (Saml2AuthenticationInfo) principal; + } + if (authentication instanceof Saml2AuthenticationInfo) { + return (Saml2AuthenticationInfo) authentication; + } + return null; + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java index 980cfa4ac6..c4550b632f 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java @@ -42,7 +42,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; @@ -149,9 +149,9 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol NameID nameId = this.nameIdBuilder.buildObject(); nameId.setValue(authentication.getName()); logoutRequest.setNameID(nameId); - if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { - Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal(); - for (String index : principal.getSessionIndexes()) { + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + for (String index : info.getSessionIndexes()) { SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject(); sessionIndex.setValue(index); logoutRequest.getSessionIndexes().add(sessionIndex); @@ -191,12 +191,9 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol if (this.logger.isTraceEnabled()) { this.logger.trace("Attempting to resolve registrationId from " + authentication); } - if (authentication == null) { - return null; - } - Object principal = authentication.getPrincipal(); - if (principal instanceof Saml2AuthenticatedPrincipal) { - return ((Saml2AuthenticatedPrincipal) principal).getRelyingPartyRegistrationId(); + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + return info.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java index 84a53005aa..975f83c930 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java @@ -24,8 +24,8 @@ import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -130,11 +130,9 @@ final class BaseOpenSamlLogoutRequestValidatorParametersResolver if (registrationId != null) { return registrationId; } - if (authentication == null) { - return null; - } - if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) { - return principal.getRelyingPartyRegistrationId(); + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + return info.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java index 4033e4d453..4fe929e372 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java @@ -46,8 +46,8 @@ import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -217,12 +217,9 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes if (this.logger.isTraceEnabled()) { this.logger.trace("Attempting to resolve registrationId from " + authentication); } - if (authentication == null) { - return null; - } - Object principal = authentication.getPrincipal(); - if (principal instanceof Saml2AuthenticatedPrincipal) { - return ((Saml2AuthenticatedPrincipal) principal).getRelyingPartyRegistrationId(); + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + return info.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java index a3a22568df..18169605ca 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java @@ -33,8 +33,8 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; @@ -329,11 +329,9 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { if (registrationId != null) { return registrationId; } - if (authentication == null) { - return null; - } - if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) { - return principal.getRelyingPartyRegistrationId(); + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + return info.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java index aae95e28c7..ce8bc94300 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java @@ -28,8 +28,8 @@ import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -144,11 +144,9 @@ public final class OpenSamlLogoutRequestValidatorParametersResolver if (registrationId != null) { return registrationId; } - if (authentication == null) { - return null; - } - if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) { - return principal.getRelyingPartyRegistrationId(); + Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); + if (info != null) { + return info.getRelyingPartyRegistrationId(); } return null; } From 02a8c416aaaf3f1093477093b65b44795060ec63 Mon Sep 17 00:00:00 2001 From: Christian Schuster Date: Mon, 6 Jun 2022 20:35:46 +0200 Subject: [PATCH 317/504] Add NameID to SAML 2.0 Authentication Info Issue gh-10820 --- .../authentication/Saml2AuthenticatedPrincipal.java | 5 +++++ .../service/authentication/Saml2AuthenticationInfo.java | 7 +++++++ .../logout/BaseOpenSamlLogoutRequestResolver.java | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java index 69eb9d7628..80e67376e6 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java @@ -77,6 +77,11 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal, Sam return null; } + @Override + default String getNameId() { + return getName(); + } + @Override default List getSessionIndexes() { return Collections.emptyList(); diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java index 309e2a909b..db412f026e 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java @@ -18,6 +18,7 @@ package org.springframework.security.saml2.provider.service.authentication; import java.util.List; +import org.opensaml.saml.saml2.core.NameID; import org.opensaml.saml.saml2.core.SessionIndex; import org.springframework.security.core.Authentication; @@ -41,6 +42,12 @@ public interface Saml2AuthenticationInfo { */ String getRelyingPartyRegistrationId(); + /** + * Get the {@link NameID} value of the authenticated principal + * @return the {@link NameID} value of the authenticated principal + */ + String getNameId(); + /** * Get the {@link SessionIndex} values of the authenticated principal * @return the {@link SessionIndex} values of the authenticated principal diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java index c4550b632f..1f0e99db32 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java @@ -147,16 +147,19 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol issuer.setValue(entityId); logoutRequest.setIssuer(issuer); NameID nameId = this.nameIdBuilder.buildObject(); - nameId.setValue(authentication.getName()); logoutRequest.setNameID(nameId); Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); if (info != null) { + nameId.setValue(info.getNameId()); for (String index : info.getSessionIndexes()) { SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject(); sessionIndex.setValue(index); logoutRequest.getSessionIndexes().add(sessionIndex); } } + else { + nameId.setValue(authentication.getName()); + } logoutRequest.setIssueInstant(Instant.now(this.clock)); this.parametersConsumer .accept(new LogoutRequestParameters(request, registration, authentication, logoutRequest)); From 9b724377ce9210a2b8cef13f3fa545284a4fcbec Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:24:12 -0600 Subject: [PATCH 318/504] Rework Saml2 Authentication Statement This commit separates the authentication principal, the assertion details, and the relying party tenant into separate components. This allows the principal to be completely decoupled from how Spring Security triggers and processes SLO. Specifically, it adds Saml2AssertionAuthentication, a new authentication implementation that allows an Object principal and a Saml2ResponseAssertionAccessor credential. It also moves the relying party registration id from Saml2AuthenticatedPrincipal to Saml2AssertionAuthentication. As such, Saml2AuthenticatedPrincipal is now deprecated in favor of placing its assertion components in Saml2ResponseAssertionAccessor and the relying party registration id in Saml2AssertionAuthentication. Closes gh-10820 --- .../saml2/Saml2LogoutConfigurer.java | 15 ++- .../http/Saml2LogoutBeanDefinitionParser.java | 15 ++- .../security/SerializationSamples.java | 15 ++- ...on.Saml2AssertionAuthentication.serialized | Bin 0 -> 1386 bytes ...tication.Saml2ResponseAssertion.serialized | Bin 0 -> 350 bytes .../ROOT/pages/migration/servlet/saml2.adoc | 54 ++++++++ .../servlet/saml2/login/authentication.adoc | 8 +- .../Saml2AssertionAuthenticationMixin.java | 59 +++++++++ .../saml2/jackson2/Saml2Jackson2Module.java | 4 + ...leSaml2ResponseAssertionAccessorMixin.java | 56 +++++++++ .../DefaultSaml2AuthenticatedPrincipal.java | 8 ++ .../Saml2AssertionAuthentication.java | 65 ++++++++++ .../Saml2AuthenticatedPrincipal.java | 13 +- .../authentication/Saml2Authentication.java | 10 +- .../Saml2AuthenticationInfo.java | 85 ------------- .../Saml2ResponseAssertion.java | 115 ++++++++++++++++++ .../Saml2ResponseAssertionAccessor.java | 65 ++++++++++ .../BaseOpenSamlLogoutRequestValidator.java | 6 +- .../BaseOpenSamlLogoutRequestResolver.java | 31 +++-- ...outRequestValidatorParametersResolver.java | 14 ++- .../BaseOpenSamlLogoutResponseResolver.java | 14 ++- .../logout/Saml2LogoutRequestFilter.java | 14 ++- ...outRequestValidatorParametersResolver.java | 10 +- .../OpenSaml5AuthenticationProvider.java | 15 +-- ...faultSaml2AuthenticatedPrincipalTests.java | 3 +- 25 files changed, 558 insertions(+), 136 deletions(-) create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication.serialized create mode 100644 config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion.serialized create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AssertionAuthenticationMixin.java create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/SimpleSaml2ResponseAssertionAccessorMixin.java create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AssertionAuthentication.java delete mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertion.java create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertionAccessor.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java index f8303a81b9..fc9950d964 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java @@ -33,7 +33,9 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolderStrategy; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutRequestValidator; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml4LogoutResponseValidator; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSaml5LogoutRequestValidator; @@ -531,7 +533,16 @@ public final class Saml2LogoutConfigurer> @Override public boolean matches(HttpServletRequest request) { Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); - return Saml2AuthenticationInfo.fromAuthentication(authentication) != null; + if (authentication == null) { + return false; + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { + return true; + } + if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor) { + return true; + } + return authentication instanceof Saml2Authentication; } } diff --git a/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java index dfeed0d981..749127027c 100644 --- a/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java @@ -31,7 +31,9 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter; import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter; @@ -236,7 +238,16 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser { @Override public boolean matches(HttpServletRequest request) { Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); - return Saml2AuthenticationInfo.fromAuthentication(authentication) != null; + if (authentication == null) { + return false; + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal) { + return true; + } + if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor) { + return true; + } + return authentication instanceof Saml2Authentication; } public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { diff --git a/config/src/test/java/org/springframework/security/SerializationSamples.java b/config/src/test/java/org/springframework/security/SerializationSamples.java index 396828ca33..d120a6ebd0 100644 --- a/config/src/test/java/org/springframework/security/SerializationSamples.java +++ b/config/src/test/java/org/springframework/security/SerializationSamples.java @@ -170,11 +170,14 @@ import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.credentials.TestSaml2X509Credentials; import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens; import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications; import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests; @@ -520,8 +523,16 @@ final class SerializationSamples { generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail"))); generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class, (r) -> TestSaml2Authentications.authentication().getPrincipal()); - generatorByClassName.put(Saml2Authentication.class, - (r) -> applyDetails(TestSaml2Authentications.authentication())); + Saml2Authentication saml2 = TestSaml2Authentications.authentication(); + generatorByClassName.put(Saml2Authentication.class, (r) -> applyDetails(saml2)); + Saml2ResponseAssertionAccessor assertion = Saml2ResponseAssertion.withResponseValue("response") + .nameId("name") + .sessionIndexes(List.of("id")) + .attributes(Map.of("key", List.of("value"))) + .build(); + generatorByClassName.put(Saml2ResponseAssertion.class, (r) -> assertion); + generatorByClassName.put(Saml2AssertionAuthentication.class, (r) -> applyDetails( + new Saml2AssertionAuthentication(assertion, authentication.getAuthorities(), "id"))); generatorByClassName.put(Saml2PostAuthenticationRequest.class, (r) -> TestSaml2PostAuthenticationRequests.create()); generatorByClassName.put(Saml2RedirectAuthenticationRequest.class, diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication.serialized new file mode 100644 index 0000000000000000000000000000000000000000..61898671f849a92212fc89c67a7c8b666bbacabc GIT binary patch literal 1386 zcmb_cJ#Q015FMYLfI-d&NPLQj0uU1DPEeA{AyJ5QQIJg%K|!>>o0v`3cgOD9Ia5UN z2ht)68Y%=SfnNYZf&vL7L<7G73PeFe!R%ff$3Zd_TyeVFot^jQy_wzo1_MgMQY`DP zN+gf!%aS#4EtadU!k{U+Zo7&##6>reaf^p2XfG%t5TNr5`FwNu0t(vH^qFwV_ z?%90x=H-{lkMHLkaC|7TPLPJcCuDCIve!ZOEV9=@rge+#^&)!~xq>Q*BZXZCL4Zod za@>bw5=EP8yUL_)SFp~NmX`EPsNsOW!dlD|EUJ4|Z6p{^B`o|mMS6r7cvO5h8~L9z zA&lSwPnhUsF;`o`Kojqht-n**ZCD3~s7?2!)~k(Mu9;c`-RsA-com}$PtLAK)8UW< z`5RE$aSlTt_M88h?B}R79Lh9mYA(FXu@FR$JSK*FLez{4Ww;g6BuBk;#>nZKP`4YZ zPR&P+IONNm)dc!vz^~!c7oLCJ7;zxyLqX7rhLIgGCdL?X{_p9!Fh?ig?%SI`$86GE zU|0>N36VP3%~F<{@c~iY2)nyz5i)w zZt~g3O$Q1->|>f{uh!J2-G+Dc!7NLt&jus9mA1Irin3u}V4|5R>cdcnbrfQXw$7sU zezfbo>69wU#f_&gE**b7YMsw(R=39It?`bA{3^EX`6Hy`Ry$}IXc@3H)le{GH0&ig U?UnOqtiwZV>X;Gtuz8*Q4Sh!7+5i9m literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion.serialized b/config/src/test/resources/serialized/7.0.x/org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion.serialized new file mode 100644 index 0000000000000000000000000000000000000000..0bc93ea8af543fd06d7917c4d55672a86718d464 GIT binary patch literal 350 zcmZXPO-jT-5QQs0BO*9DZoNYXTskY!O&}r|aB$fsWo#$YX}clFlNDIP_< zgmwTt6G1+h%8)owh?5k(#^G%3tV<~E(ojMDqabai}pYm+YPEl>vcP* z3We z(o753&>o%F413?BR_Z1z{f2J*bld)9U&yw{JGh6qfH5JF$K<+37gBfsq!x;J>Wu$y z5>O(b#BtZQCED4;^XuXM(` details from the principal. +This allows Spring Security to retrieve needed assertion details to perform Single Logout. + +This deprecates `Saml2AuthenticatedPrincipal`. +You no longer need to implement it to use `Saml2Authentication`. + +Instead, the credential implements `Saml2ResponseAssertionAccessor`, which Spring Security 7 favors when determining the appropriate action based on the authentication. + +This change is made automatically for you when using the defaults. + +If this causes you trouble when upgrading, you can publish a custom `ResponseAuhenticationConverter` to return a `Saml2Authentication` instead of returning a `Saml2AssertionAuthentication` like so: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +OpenSaml5AuthenticationProvider authenticationProvider() { + OpenSaml5AuthenticationProvider authenticationProvider = + new OpenSaml5AuthenticationProvider(); + ResponseAuthenticationConverter defaults = new ResponseAuthenticationConverter(); + authenticationProvider.setResponseAuthenticationConverter( + defaults.andThen((authentication) -> new Saml2Authentication( + authentication.getPrincipal(), + authentication.getSaml2Response(), + authentication.getAuthorities()))); + return authenticationProvider; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationProvider(): OpenSaml5AuthenticationProvider { + val authenticationProvider = OpenSaml5AuthenticationProvider() + val defaults = ResponseAuthenticationConverter() + authenticationProvider.setResponseAuthenticationConverter( + defaults.andThen { authentication -> + Saml2Authentication(authentication.getPrincipal(), + authentication.getSaml2Response(), + authentication.getAuthorities()) + }) + return authenticationProvider +} +---- +====== + +If you are constructing a `Saml2Authentication` instance yourself, consider changing to `Saml2AssertionAuthentication` to get the same benefit as the current default. diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index 1c517914dc..400a66ad3a 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -341,8 +341,10 @@ class MyUserDetailsResponseAuthenticationConverter implements Converter UserDetails principal = this.userDetailsService.loadByUsername(username); <2> String saml2Response = authentication.getSaml2Response(); + Saml2ResponseAssertionAccessor assertion = new OpenSamlResponseAssertionAccessor( + saml2Response, CollectionUtils.getFirst(response.getAssertions())); Collection authorities = principal.getAuthorities(); - return new Saml2Authentication((AuthenticatedPrincipal) userDetails, saml2Response, authorities); <3> + return new Saml2AssertionAuthentication(userDetails, assertion, authorities); <3> } } @@ -361,8 +363,10 @@ open class MyUserDetailsResponseAuthenticationConverter(val delegate: ResponseAu val authentication = this.delegate.convert(responseToken) <1> val principal = this.userDetailsService.loadByUsername(username) <2> val saml2Response = authentication.getSaml2Response() + val assertion = OpenSamlResponseAssertionAccessor( + saml2Response, CollectionUtils.getFirst(response.getAssertions())) val authorities = principal.getAuthorities() - return Saml2Authentication(userDetails as AuthenticatedPrincipal, saml2Response, authorities) <3> + return Saml2AssertionAuthentication(userDetails, assertion, authorities) <3> } } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AssertionAuthenticationMixin.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AssertionAuthenticationMixin.java new file mode 100644 index 0000000000..d3d3156446 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AssertionAuthenticationMixin.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.jackson2; + +import java.util.Collection; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; + +/** + * Jackson Mixin class helps in serialize/deserialize + * {@link Saml2AssertionAuthentication}. + * + *

+ *     ObjectMapper mapper = new ObjectMapper();
+ *     mapper.registerModule(new Saml2Jackson2Module());
+ * 
+ * + * @author Josh Cummings + * @since 7.0 + * @see Saml2Jackson2Module + * @see SecurityJackson2Modules + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE) +@JsonIgnoreProperties(value = { "authenticated" }, ignoreUnknown = true) +class Saml2AssertionAuthenticationMixin { + + @JsonCreator + Saml2AssertionAuthenticationMixin(@JsonProperty("principal") Object principal, + @JsonProperty("assertion") Saml2ResponseAssertionAccessor assertion, + @JsonProperty("authorities") Collection authorities, + @JsonProperty("relyingPartyRegistrationId") String relyingPartyRegistrationId) { + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java index 3d99fc2cfa..b53fcd15bc 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java @@ -22,10 +22,12 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; /** @@ -49,6 +51,8 @@ public class Saml2Jackson2Module extends SimpleModule { @Override public void setupModule(SetupContext context) { context.setMixInAnnotations(Saml2Authentication.class, Saml2AuthenticationMixin.class); + context.setMixInAnnotations(Saml2AssertionAuthentication.class, Saml2AssertionAuthenticationMixin.class); + context.setMixInAnnotations(Saml2ResponseAssertion.class, SimpleSaml2ResponseAssertionAccessorMixin.class); context.setMixInAnnotations(DefaultSaml2AuthenticatedPrincipal.class, DefaultSaml2AuthenticatedPrincipalMixin.class); context.setMixInAnnotations(Saml2LogoutRequest.class, Saml2LogoutRequestMixin.class); diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/SimpleSaml2ResponseAssertionAccessorMixin.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/SimpleSaml2ResponseAssertionAccessorMixin.java new file mode 100644 index 0000000000..7f4d02b4a0 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/SimpleSaml2ResponseAssertionAccessorMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.jackson2; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertion; + +/** + * Jackson Mixin class helps in serialize/deserialize {@link Saml2ResponseAssertion}. + * + *
+ *     ObjectMapper mapper = new ObjectMapper();
+ *     mapper.registerModule(new Saml2Jackson2Module());
+ * 
+ * + * @author Josh Cummings + * @since 7.0 + * @see Saml2Jackson2Module + * @see SecurityJackson2Modules + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE) +@JsonIgnoreProperties(value = { "authenticated" }, ignoreUnknown = true) +class SimpleSaml2ResponseAssertionAccessorMixin { + + @JsonCreator + SimpleSaml2ResponseAssertionAccessorMixin(@JsonProperty("responseValue") String responseValue, + @JsonProperty("nameId") String nameId, @JsonProperty("sessionIndexes") List sessionIndexes, + @JsonProperty("attributes") Map> attributes) { + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipal.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipal.java index d99f640cb5..d2e9658fd0 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipal.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipal.java @@ -30,7 +30,9 @@ import org.springframework.util.Assert; * * @author Clement Stoquart * @since 5.4 + * @deprecated Please use {@link Saml2ResponseAssertionAccessor} */ +@Deprecated public class DefaultSaml2AuthenticatedPrincipal implements Saml2AuthenticatedPrincipal, Serializable { @Serial @@ -58,6 +60,12 @@ public class DefaultSaml2AuthenticatedPrincipal implements Saml2AuthenticatedPri this.sessionIndexes = sessionIndexes; } + public DefaultSaml2AuthenticatedPrincipal(String name, Saml2ResponseAssertionAccessor assertion) { + this.name = name; + this.attributes = assertion.getAttributes(); + this.sessionIndexes = assertion.getSessionIndexes(); + } + @Override public String getName() { return this.name; diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AssertionAuthentication.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AssertionAuthentication.java new file mode 100644 index 0000000000..c38cfbfbd1 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AssertionAuthentication.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.authentication; + +import java.io.Serial; +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; + +/** + * An authentication based off of a SAML 2.0 Assertion + * + * @author Josh Cummings + * @since 7.0 + * @see Saml2ResponseAssertionAccessor + * @see Saml2ResponseAssertion + */ +public class Saml2AssertionAuthentication extends Saml2Authentication { + + @Serial + private static final long serialVersionUID = -4194323643788693205L; + + private final Saml2ResponseAssertionAccessor assertion; + + private final String relyingPartyRegistrationId; + + public Saml2AssertionAuthentication(Saml2ResponseAssertionAccessor assertion, + Collection authorities, String relyingPartyRegistrationId) { + super(assertion, assertion.getResponseValue(), authorities); + this.assertion = assertion; + this.relyingPartyRegistrationId = relyingPartyRegistrationId; + } + + public Saml2AssertionAuthentication(Object principal, Saml2ResponseAssertionAccessor assertion, + Collection authorities, String relyingPartyRegistrationId) { + super(principal, assertion.getResponseValue(), authorities); + this.assertion = assertion; + this.relyingPartyRegistrationId = relyingPartyRegistrationId; + setAuthenticated(true); + } + + @Override + public Saml2ResponseAssertionAccessor getCredentials() { + return this.assertion; + } + + public String getRelyingPartyRegistrationId() { + return this.relyingPartyRegistrationId; + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java index 80e67376e6..6f3e32c888 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java @@ -30,8 +30,12 @@ import org.springframework.util.CollectionUtils; * * @author Clement Stoquart * @since 5.2.2 + * @deprecated Please use + * {@link Saml2AssertionAuthentication#getRelyingPartyRegistrationId()} and + * {@link Saml2ResponseAssertionAccessor} instead */ -public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal, Saml2AuthenticationInfo { +@Deprecated +public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal { /** * Get the first value of Saml2 token attribute by name @@ -72,17 +76,10 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal, Sam * @return the {@link RelyingPartyRegistration} identifier * @since 5.6 */ - @Override default String getRelyingPartyRegistrationId() { return null; } - @Override - default String getNameId() { - return getName(); - } - - @Override default List getSessionIndexes() { return Collections.emptyList(); } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2Authentication.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2Authentication.java index 2292f52a37..e628f260e8 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2Authentication.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2Authentication.java @@ -41,7 +41,7 @@ public class Saml2Authentication extends AbstractAuthenticationToken { @Serial private static final long serialVersionUID = 405897702378720477L; - private final AuthenticatedPrincipal principal; + private final Object principal; private final String saml2Response; @@ -61,6 +61,14 @@ public class Saml2Authentication extends AbstractAuthenticationToken { setAuthenticated(true); } + public Saml2Authentication(Object principal, String saml2Response, + Collection authorities) { + super(authorities); + this.principal = principal; + this.saml2Response = saml2Response; + setAuthenticated(true); + } + @Override public Object getPrincipal() { return this.principal; diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java deleted file mode 100644 index db412f026e..0000000000 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2AuthenticationInfo.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.saml2.provider.service.authentication; - -import java.util.List; - -import org.opensaml.saml.saml2.core.NameID; -import org.opensaml.saml.saml2.core.SessionIndex; - -import org.springframework.security.core.Authentication; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; - -/** - * Additional SAML 2.0 authentication information - * - *

- * SAML 2.0 Single Logout requires that the {@link Authentication#getPrincipal() - * authenticated principal} or the {@link Authentication} itself implements this - * interface. - * - * @author Christian Schuster - */ -public interface Saml2AuthenticationInfo { - - /** - * Get the {@link RelyingPartyRegistration} identifier - * @return the {@link RelyingPartyRegistration} identifier - */ - String getRelyingPartyRegistrationId(); - - /** - * Get the {@link NameID} value of the authenticated principal - * @return the {@link NameID} value of the authenticated principal - */ - String getNameId(); - - /** - * Get the {@link SessionIndex} values of the authenticated principal - * @return the {@link SessionIndex} values of the authenticated principal - */ - List getSessionIndexes(); - - /** - * Try to obtain a {@link Saml2AuthenticationInfo} instance from an - * {@link Authentication} - * - *

- * The result is either the {@link Authentication#getPrincipal() authenticated - * principal}, the {@link Authentication} itself, or {@code null}. - * - *

- * Returning {@code null} indicates that the given {@link Authentication} does not - * represent a SAML 2.0 authentication. - * @param authentication the {@link Authentication} - * @return the {@link Saml2AuthenticationInfo} or {@code null} if unavailable - */ - static Saml2AuthenticationInfo fromAuthentication(Authentication authentication) { - if (authentication == null) { - return null; - } - Object principal = authentication.getPrincipal(); - if (principal instanceof Saml2AuthenticationInfo) { - return (Saml2AuthenticationInfo) principal; - } - if (authentication instanceof Saml2AuthenticationInfo) { - return (Saml2AuthenticationInfo) authentication; - } - return null; - } - -} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertion.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertion.java new file mode 100644 index 0000000000..ea5dd2a8a9 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertion.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.authentication; + +import java.io.Serial; +import java.util.List; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * An OpenSAML-based implementation of {@link Saml2ResponseAssertionAccessor} + * + * @author Josh Cummings + * @since 7.0 + */ +public class Saml2ResponseAssertion implements Saml2ResponseAssertionAccessor { + + @Serial + private static final long serialVersionUID = -7505233045395024212L; + + private final String responseValue; + + private final String nameId; + + private final List sessionIndexes; + + private final Map> attributes; + + Saml2ResponseAssertion(String responseValue, String nameId, List sessionIndexes, + Map> attributes) { + Assert.notNull(responseValue, "response value cannot be null"); + Assert.notNull(nameId, "nameId cannot be null"); + Assert.notNull(sessionIndexes, "sessionIndexes cannot be null"); + Assert.notNull(attributes, "attributes cannot be null"); + this.responseValue = responseValue; + this.nameId = nameId; + this.sessionIndexes = sessionIndexes; + this.attributes = attributes; + } + + public static Builder withResponseValue(String responseValue) { + return new Builder(responseValue); + } + + @Override + public String getNameId() { + return this.nameId; + } + + @Override + public List getSessionIndexes() { + return this.sessionIndexes; + } + + @Override + public Map> getAttributes() { + return this.attributes; + } + + @Override + public String getResponseValue() { + return this.responseValue; + } + + public static final class Builder { + + private final String responseValue; + + private String nameId; + + private List sessionIndexes = List.of(); + + private Map> attributes = Map.of(); + + Builder(String responseValue) { + this.responseValue = responseValue; + } + + public Builder nameId(String nameId) { + this.nameId = nameId; + return this; + } + + public Builder sessionIndexes(List sessionIndexes) { + this.sessionIndexes = sessionIndexes; + return this; + } + + public Builder attributes(Map> attributes) { + this.attributes = attributes; + return this; + } + + public Saml2ResponseAssertion build() { + return new Saml2ResponseAssertion(this.responseValue, this.nameId, this.sessionIndexes, this.attributes); + } + + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertionAccessor.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertionAccessor.java new file mode 100644 index 0000000000..f137b79848 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/Saml2ResponseAssertionAccessor.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.authentication; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +import org.springframework.util.CollectionUtils; + +/** + * An interface that represents key details from a SAML 2.0 Assertion + * + * @author Josh Cummings + * @since 7.0 + * @see Saml2ResponseAssertion + */ +public interface Saml2ResponseAssertionAccessor extends Serializable { + + String getNameId(); + + List getSessionIndexes(); + + /** + * Get the first value of Saml2 token attribute by name + * @param name the name of the attribute + * @param the type of the attribute + * @return the first attribute value or {@code null} otherwise + */ + @Nullable default A getFirstAttribute(String name) { + List values = getAttribute(name); + return CollectionUtils.firstElement(values); + } + + /** + * Get the Saml2 token attribute by name + * @param name the name of the attribute + * @param the type of the attribute + * @return the attribute or {@code null} otherwise + */ + @Nullable default List getAttribute(String name) { + return (List) getAttributes().get(name); + } + + Map> getAttributes(); + + String getResponseValue(); + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/logout/BaseOpenSamlLogoutRequestValidator.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/logout/BaseOpenSamlLogoutRequestValidator.java index b96cb947c6..9165113684 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/logout/BaseOpenSamlLogoutRequestValidator.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/logout/BaseOpenSamlLogoutRequestValidator.java @@ -27,6 +27,7 @@ import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2X509Credential; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlOperations.VerificationConfigurer; import org.springframework.security.saml2.provider.service.authentication.logout.OpenSamlOperations.VerificationConfigurer.RedirectParameters; import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata; @@ -142,8 +143,9 @@ class BaseOpenSamlLogoutRequestValidator implements Saml2LogoutRequestValidator } private void validateNameId(NameID nameId, Authentication authentication, Collection errors) { - String name = nameId.getValue(); - if (!name.equals(authentication.getName())) { + String name = (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor assertion) + ? assertion.getNameId() : authentication.getName(); + if (!nameId.getValue().equals(name)) { errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_REQUEST, "Failed to match subject in LogoutRequest with currently logged in user")); } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java index 1f0e99db32..def1ab7afe 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestResolver.java @@ -42,7 +42,9 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2ParameterNames; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; +import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; @@ -148,17 +150,25 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol logoutRequest.setIssuer(issuer); NameID nameId = this.nameIdBuilder.buildObject(); logoutRequest.setNameID(nameId); - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { + if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor info) { nameId.setValue(info.getNameId()); + } + else { + nameId.setValue(authentication.getName()); + } + if (authentication.getCredentials() instanceof Saml2ResponseAssertionAccessor info) { for (String index : info.getSessionIndexes()) { SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject(); sessionIndex.setValue(index); logoutRequest.getSessionIndexes().add(sessionIndex); } } - else { - nameId.setValue(authentication.getName()); + else if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal info) { + for (String index : info.getSessionIndexes()) { + SessionIndex sessionIndex = this.sessionIndexBuilder.buildObject(); + sessionIndex.setValue(index); + logoutRequest.getSessionIndexes().add(sessionIndex); + } } logoutRequest.setIssueInstant(Instant.now(this.clock)); this.parametersConsumer @@ -194,9 +204,14 @@ final class BaseOpenSamlLogoutRequestResolver implements Saml2LogoutRequestResol if (this.logger.isTraceEnabled()) { this.logger.trace("Attempting to resolve registrationId from " + authentication); } - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { - return info.getRelyingPartyRegistrationId(); + if (authentication == null) { + return null; + } + if (authentication instanceof Saml2AssertionAuthentication response) { + return response.getRelyingPartyRegistrationId(); + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) { + return principal.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java index 975f83c930..3fc54e88bf 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutRequestValidatorParametersResolver.java @@ -24,8 +24,9 @@ import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -130,9 +131,14 @@ final class BaseOpenSamlLogoutRequestValidatorParametersResolver if (registrationId != null) { return registrationId; } - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { - return info.getRelyingPartyRegistrationId(); + if (authentication == null) { + return null; + } + if (authentication instanceof Saml2AssertionAuthentication saml2) { + return saml2.getRelyingPartyRegistrationId(); + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal saml2) { + return saml2.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java index 4fe929e372..48dd0bc47a 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/BaseOpenSamlLogoutResponseResolver.java @@ -46,8 +46,9 @@ import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; @@ -217,9 +218,14 @@ final class BaseOpenSamlLogoutResponseResolver implements Saml2LogoutResponseRes if (this.logger.isTraceEnabled()) { this.logger.trace("Attempting to resolve registrationId from " + authentication); } - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { - return info.getRelyingPartyRegistrationId(); + if (authentication == null) { + return null; + } + if (authentication instanceof Saml2AssertionAuthentication saml2) { + return saml2.getRelyingPartyRegistrationId(); + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal saml2) { + return saml2.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java index 18169605ca..29fe0921c5 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutRequestFilter.java @@ -33,8 +33,9 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.Saml2AssertionAuthentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidator; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; @@ -329,9 +330,14 @@ public final class Saml2LogoutRequestFilter extends OncePerRequestFilter { if (registrationId != null) { return registrationId; } - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { - return info.getRelyingPartyRegistrationId(); + if (authentication == null) { + return null; + } + if (authentication instanceof Saml2AssertionAuthentication saml2) { + return saml2.getRelyingPartyRegistrationId(); + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal saml2) { + return saml2.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java index ce8bc94300..aae95e28c7 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlLogoutRequestValidatorParametersResolver.java @@ -28,8 +28,8 @@ import org.springframework.security.core.Authentication; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ParameterNames; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; -import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationInfo; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequestValidatorParameters; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; @@ -144,9 +144,11 @@ public final class OpenSamlLogoutRequestValidatorParametersResolver if (registrationId != null) { return registrationId; } - Saml2AuthenticationInfo info = Saml2AuthenticationInfo.fromAuthentication(authentication); - if (info != null) { - return info.getRelyingPartyRegistrationId(); + if (authentication == null) { + return null; + } + if (authentication.getPrincipal() instanceof Saml2AuthenticatedPrincipal principal) { + return principal.getRelyingPartyRegistrationId(); } return null; } diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java index d2dbb5ba0c..6d49c6ef2f 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProvider.java @@ -893,14 +893,15 @@ public final class OpenSaml5AuthenticationProvider implements AuthenticationProv Saml2AuthenticationToken token = responseToken.token; Assertion assertion = CollectionUtils.firstElement(response.getAssertions()); String username = this.principalNameConverter.convert(assertion); - Map> attributes = BaseOpenSamlAuthenticationProvider.getAssertionAttributes(assertion); - List sessionIndexes = BaseOpenSamlAuthenticationProvider.getSessionIndexes(assertion); - DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes, - sessionIndexes); String registrationId = responseToken.token.getRelyingPartyRegistration().getRegistrationId(); - principal.setRelyingPartyRegistrationId(registrationId); - return new Saml2Authentication(principal, token.getSaml2Response(), - this.grantedAuthoritiesConverter.convert(assertion)); + Saml2ResponseAssertionAccessor accessor = Saml2ResponseAssertion.withResponseValue(token.getSaml2Response()) + .nameId(authenticatedPrincipal(assertion)) + .sessionIndexes(BaseOpenSamlAuthenticationProvider.getSessionIndexes(assertion)) + .attributes(BaseOpenSamlAuthenticationProvider.getAssertionAttributes(assertion)) + .build(); + Saml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, accessor); + Collection authorities = this.grantedAuthoritiesConverter.convert(assertion); + return new Saml2AssertionAuthentication(principal, accessor, authorities, registrationId); } /** diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java index 4ea06059a6..75ab69d108 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java @@ -48,7 +48,8 @@ public class DefaultSaml2AuthenticatedPrincipalTests { @Test public void createDefaultSaml2AuthenticatedPrincipalWhenAttributesNullThenException() { - assertThatIllegalArgumentException().isThrownBy(() -> new DefaultSaml2AuthenticatedPrincipal("user", null)) + assertThatIllegalArgumentException() + .isThrownBy(() -> new DefaultSaml2AuthenticatedPrincipal("user", (Map>) null)) .withMessageContaining("attributes cannot be null"); } From 220f49d86e83850c6f72678b34f4e941e811e9e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:14:31 +0000 Subject: [PATCH 319/504] Bump io.projectreactor:reactor-bom from 2025.0.0-M3 to 2025.0.0-M4 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2025.0.0-M3 to 2025.0.0-M4. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2025.0.0-M3...2025.0.0-M4) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2025.0.0-M4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2125a073ab..fc72627f88 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" io-mockk = "io.mockk:mockk:1.14.2" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M3" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 60f729156b7853f47a08e18305871aab34f425ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:15:08 +0000 Subject: [PATCH 320/504] Bump org.hibernate.orm:hibernate-core from 7.0.0.Final to 7.0.1.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.0.Final to 7.0.1.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.1/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.0...7.0.1) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.1.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2125a073ab..18e7c2c9bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.0.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From cc40879f05d7f451f2af04df63a3beb495252f1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:35:43 +0000 Subject: [PATCH 321/504] Bump com.fasterxml.jackson:jackson-bom from 2.18.4 to 2.18.4.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.4 to 2.18.4.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.4...jackson-bom-2.18.4.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.18.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d4052d35a..4264144337 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "6.2.7" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 53ce08d79d854a7416944d0d3b90c81cc0f8ee09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:36:18 +0000 Subject: [PATCH 322/504] Bump io.projectreactor:reactor-bom from 2023.0.18 to 2023.0.19 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.18 to 2023.0.19. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.18...2023.0.19) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d4052d35a..0eb6a6fc0f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" io-mockk = "io.mockk:mockk:1.13.17" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.18" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 7f36155b474899b25f05675b3a0584479cf85125 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 03:59:26 +0000 Subject: [PATCH 323/504] Bump io.projectreactor:reactor-bom from 2023.0.18 to 2023.0.19 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.18 to 2023.0.19. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.18...2023.0.19) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 779486eaee..94b8454fc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,7 +28,7 @@ com-unboundid-unboundid-ldapsdk = "com.unboundid:unboundid-ldapsdk:6.0.11" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.12.13" io-mockk = "io.mockk:mockk:1.13.17" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.18" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 195fb7253c51102a319d13fce82983a804c014f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 04:06:24 +0000 Subject: [PATCH 324/504] Bump io.projectreactor:reactor-bom from 2023.0.18 to 2023.0.19 Bumps [io.projectreactor:reactor-bom](https://github.com/reactor/reactor) from 2023.0.18 to 2023.0.19. - [Release notes](https://github.com/reactor/reactor/releases) - [Commits](https://github.com/reactor/reactor/compare/2023.0.18...2023.0.19) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-bom dependency-version: 2023.0.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ba6d0173db..05ab22cbb4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" io-mockk = "io.mockk:mockk:1.14.2" -io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.18" +io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" } From 9be7b374727c5724fa65f48e95639968cc5c1c06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 04:06:48 +0000 Subject: [PATCH 325/504] Bump com.fasterxml.jackson:jackson-bom from 2.18.4 to 2.18.4.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.4 to 2.18.4.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.4...jackson-bom-2.18.4.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.18.4.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ba6d0173db..8b8a60fb5c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "6.2.7" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.18.4.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 16fd24c0025f2c1d77eafd59ddd59a0a42730e81 Mon Sep 17 00:00:00 2001 From: "chao.wang" Date: Thu, 8 May 2025 17:24:30 +0800 Subject: [PATCH 326/504] Add JdbcAssertingPartyMetadataRepository Closes gh-16012 Signed-off-by: chao.wang --- ...ing-security-saml2-service-provider.gradle | 2 + .../JdbcAssertingPartyMetadataRepository.java | 190 ++++++++++++++++++ ...serting-party-metadata-schema-postgres.sql | 14 ++ .../saml2-asserting-party-metadata-schema.sql | 14 ++ ...AssertingPartyMetadataRepositoryTests.java | 177 ++++++++++++++++ .../src/test/resources/rsa.crt | 23 +++ 6 files changed, 420 insertions(+) create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java create mode 100644 saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql create mode 100644 saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql create mode 100644 saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java create mode 100644 saml2/saml2-service-provider/src/test/resources/rsa.crt diff --git a/saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle b/saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle index 8b40d415d6..b05c1bbd57 100644 --- a/saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle +++ b/saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle @@ -106,6 +106,7 @@ dependencies { provided 'jakarta.servlet:jakarta.servlet-api' optional 'com.fasterxml.jackson.core:jackson-databind' + optional 'org.springframework:spring-jdbc' testImplementation 'com.squareup.okhttp3:mockwebserver' testImplementation "org.assertj:assertj-core" @@ -118,6 +119,7 @@ dependencies { testImplementation "org.springframework:spring-test" testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'org.hsqldb:hsqldb' } jar { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java new file mode 100644 index 0000000000..620e6bdf2e --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java @@ -0,0 +1,190 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.provider.service.registration; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.log.LogMessage; +import org.springframework.core.serializer.DefaultDeserializer; +import org.springframework.core.serializer.Deserializer; +import org.springframework.jdbc.core.ArgumentPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SqlParameterValue; +import org.springframework.security.saml2.core.Saml2X509Credential; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; +import org.springframework.util.Assert; + +/** + * A JDBC implementation of {@link AssertingPartyMetadataRepository}. + * + * @author Cathy Wang + * @since 7.0 + */ +public final class JdbcAssertingPartyMetadataRepository implements AssertingPartyMetadataRepository { + + private final JdbcOperations jdbcOperations; + + private RowMapper assertingPartyMetadataRowMapper = new AssertingPartyMetadataRowMapper( + ResultSet::getBytes); + + // @formatter:off + static final String COLUMN_NAMES = "entity_id, " + + "singlesignon_url, " + + "singlesignon_binding, " + + "singlesignon_sign_request, " + + "signing_algorithms, " + + "verification_credentials, " + + "encryption_credentials, " + + "singlelogout_url, " + + "singlelogout_response_url, " + + "singlelogout_binding"; + // @formatter:on + + private static final String TABLE_NAME = "saml2_asserting_party_metadata"; + + private static final String ENTITY_ID_FILTER = "entity_id = ?"; + + // @formatter:off + private static final String LOAD_BY_ID_SQL = "SELECT " + COLUMN_NAMES + + " FROM " + TABLE_NAME + + " WHERE " + ENTITY_ID_FILTER; + + private static final String LOAD_ALL_SQL = "SELECT " + COLUMN_NAMES + + " FROM " + TABLE_NAME; + // @formatter:on + + /** + * Constructs a {@code JdbcRelyingPartyRegistrationRepository} using the provided + * parameters. + * @param jdbcOperations the JDBC operations + */ + public JdbcAssertingPartyMetadataRepository(JdbcOperations jdbcOperations) { + Assert.notNull(jdbcOperations, "jdbcOperations cannot be null"); + this.jdbcOperations = jdbcOperations; + } + + /** + * Sets the {@link RowMapper} used for mapping the current row in + * {@code java.sql.ResultSet} to {@link AssertingPartyMetadata}. The default is + * {@link AssertingPartyMetadataRowMapper}. + * @param assertingPartyMetadataRowMapper the {@link RowMapper} used for mapping the + * current row in {@code java.sql.ResultSet} to {@link AssertingPartyMetadata} + */ + public void setAssertingPartyMetadataRowMapper(RowMapper assertingPartyMetadataRowMapper) { + Assert.notNull(assertingPartyMetadataRowMapper, "assertingPartyMetadataRowMapper cannot be null"); + this.assertingPartyMetadataRowMapper = assertingPartyMetadataRowMapper; + } + + @Override + public AssertingPartyMetadata findByEntityId(String entityId) { + Assert.hasText(entityId, "entityId cannot be empty"); + SqlParameterValue[] parameters = new SqlParameterValue[] { new SqlParameterValue(Types.VARCHAR, entityId) }; + PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters); + List result = this.jdbcOperations.query(LOAD_BY_ID_SQL, pss, + this.assertingPartyMetadataRowMapper); + return !result.isEmpty() ? result.get(0) : null; + } + + @Override + public Iterator iterator() { + List result = this.jdbcOperations.query(LOAD_ALL_SQL, + this.assertingPartyMetadataRowMapper); + return result.iterator(); + } + + /** + * The default {@link RowMapper} that maps the current row in + * {@code java.sql.ResultSet} to {@link AssertingPartyMetadata}. + */ + private static final class AssertingPartyMetadataRowMapper implements RowMapper { + + private final Log logger = LogFactory.getLog(AssertingPartyMetadataRowMapper.class); + + private final Deserializer deserializer = new DefaultDeserializer(); + + private final GetBytes getBytes; + + AssertingPartyMetadataRowMapper(GetBytes getBytes) { + this.getBytes = getBytes; + } + + @Override + public AssertingPartyMetadata mapRow(ResultSet rs, int rowNum) throws SQLException { + String entityId = rs.getString("entity_id"); + String singleSignOnUrl = rs.getString("singlesignon_url"); + Saml2MessageBinding singleSignOnBinding = Saml2MessageBinding.from(rs.getString("singlesignon_binding")); + boolean singleSignOnSignRequest = rs.getBoolean("singlesignon_sign_request"); + String singleLogoutUrl = rs.getString("singlelogout_url"); + String singleLogoutResponseUrl = rs.getString("singlelogout_response_url"); + Saml2MessageBinding singleLogoutBinding = Saml2MessageBinding.from(rs.getString("singlelogout_binding")); + byte[] signingAlgorithmsBytes = this.getBytes.getBytes(rs, "signing_algorithms"); + byte[] verificationCredentialsBytes = this.getBytes.getBytes(rs, "verification_credentials"); + byte[] encryptionCredentialsBytes = this.getBytes.getBytes(rs, "encryption_credentials"); + + AssertingPartyMetadata.Builder builder = new AssertingPartyDetails.Builder(); + try { + if (signingAlgorithmsBytes != null) { + List signingAlgorithms = (List) this.deserializer + .deserializeFromByteArray(signingAlgorithmsBytes); + builder.signingAlgorithms((algorithms) -> algorithms.addAll(signingAlgorithms)); + } + if (verificationCredentialsBytes != null) { + Collection verificationCredentials = (Collection) this.deserializer + .deserializeFromByteArray(verificationCredentialsBytes); + builder.verificationX509Credentials((credentials) -> credentials.addAll(verificationCredentials)); + } + if (encryptionCredentialsBytes != null) { + Collection encryptionCredentials = (Collection) this.deserializer + .deserializeFromByteArray(encryptionCredentialsBytes); + builder.encryptionX509Credentials((credentials) -> credentials.addAll(encryptionCredentials)); + } + } + catch (Exception ex) { + this.logger.debug(LogMessage.format("Parsing serialized credentials for entity %s failed", entityId), + ex); + return null; + } + + builder.entityId(entityId) + .wantAuthnRequestsSigned(singleSignOnSignRequest) + .singleSignOnServiceLocation(singleSignOnUrl) + .singleSignOnServiceBinding(singleSignOnBinding) + .singleLogoutServiceLocation(singleLogoutUrl) + .singleLogoutServiceBinding(singleLogoutBinding) + .singleLogoutServiceResponseLocation(singleLogoutResponseUrl); + return builder.build(); + } + + } + + private interface GetBytes { + + byte[] getBytes(ResultSet rs, String columnName) throws SQLException; + + } + +} diff --git a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql new file mode 100644 index 0000000000..ffa047fe7b --- /dev/null +++ b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql @@ -0,0 +1,14 @@ +CREATE TABLE saml2_asserting_party_metadata +( + entity_id VARCHAR(1000) NOT NULL, + singlesignon_url VARCHAR(1000) NOT NULL, + singlesignon_binding VARCHAR(100), + singlesignon_sign_request boolean, + signing_algorithms BYTEA, + verification_credentials BYTEA NOT NULL, + encryption_credentials BYTEA, + singlelogout_url VARCHAR(1000), + singlelogout_response_url VARCHAR(1000), + singlelogout_binding VARCHAR(100), + PRIMARY KEY (entity_id) +); diff --git a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql new file mode 100644 index 0000000000..2fd6cb8cdf --- /dev/null +++ b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql @@ -0,0 +1,14 @@ +CREATE TABLE saml2_asserting_party_metadata +( + entity_id VARCHAR(1000) NOT NULL, + singlesignon_url VARCHAR(1000) NOT NULL, + singlesignon_binding VARCHAR(100), + singlesignon_sign_request boolean, + signing_algorithms blob, + verification_credentials blob NOT NULL, + encryption_credentials blob, + singlelogout_url VARCHAR(1000), + singlelogout_response_url VARCHAR(1000), + singlelogout_binding VARCHAR(100), + PRIMARY KEY (entity_id) +); diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java new file mode 100644 index 0000000000..c734bcb236 --- /dev/null +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java @@ -0,0 +1,177 @@ +package org.springframework.security.saml2.provider.service.registration; + +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.serializer.DefaultSerializer; +import org.springframework.core.serializer.Serializer; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.security.saml2.core.Saml2X509Credential; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +/** + * Tests for {@link JdbcAssertingPartyMetadataRepository} + */ +class JdbcAssertingPartyMetadataRepositoryTests { + + private static final String SCHEMA_SQL_RESOURCE = "org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql"; + + private static final String SAVE_SQL = "INSERT INTO saml2_asserting_party_metadata (" + + JdbcAssertingPartyMetadataRepository.COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + private static final String ENTITY_ID = "https://localhost/simplesaml/saml2/idp/metadata.php"; + + private static final String SINGLE_SIGNON_URL = "https://localhost/SSO"; + + private static final String SINGLE_SIGNON_BINDING = Saml2MessageBinding.REDIRECT.getUrn(); + + private static final boolean SINGLE_SIGNON_SIGN_REQUEST = false; + + private static final String SINGLE_LOGOUT_URL = "https://localhost/SLO"; + + private static final String SINGLE_LOGOUT_RESPONSE_URL = "https://localhost/SLO/response"; + + private static final String SINGLE_LOGOUT_BINDING = Saml2MessageBinding.REDIRECT.getUrn(); + + private static final List SIGNING_ALGORITHMS = List.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"); + + private X509Certificate certificate; + + private EmbeddedDatabase db; + + private JdbcAssertingPartyMetadataRepository repository; + + private JdbcOperations jdbcOperations; + + private final Serializer serializer = new DefaultSerializer(); + + @BeforeEach + public void setUp() throws Exception { + this.db = createDb(); + this.jdbcOperations = new JdbcTemplate(this.db); + this.repository = new JdbcAssertingPartyMetadataRepository(this.jdbcOperations); + this.certificate = loadCertificate("rsa.crt"); + } + + @AfterEach + public void tearDown() { + this.db.shutdown(); + } + + @Test + void constructorWhenJdbcOperationsIsNullThenThrowIllegalArgumentException() { + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> new JdbcAssertingPartyMetadataRepository(null)) + .withMessage("jdbcOperations cannot be null"); + // @formatter:on + } + + @Test + void findByEntityIdWhenEntityIdIsNullThenThrowIllegalArgumentException() { + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.repository.findByEntityId(null)) + .withMessage("entityId cannot be empty"); + // @formatter:on + } + + @Test + void findByEntityId() throws IOException { + this.jdbcOperations.update(SAVE_SQL, ENTITY_ID, SINGLE_SIGNON_URL, SINGLE_SIGNON_BINDING, + SINGLE_SIGNON_SIGN_REQUEST, this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, + SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); + + AssertingPartyMetadata found = this.repository.findByEntityId(ENTITY_ID); + + assertThat(found).isNotNull(); + assertThat(found.getEntityId()).isEqualTo(ENTITY_ID); + assertThat(found.getSingleSignOnServiceLocation()).isEqualTo(SINGLE_SIGNON_URL); + assertThat(found.getSingleSignOnServiceBinding().getUrn()).isEqualTo(SINGLE_SIGNON_BINDING); + assertThat(found.getWantAuthnRequestsSigned()).isEqualTo(SINGLE_SIGNON_SIGN_REQUEST); + assertThat(found.getSingleLogoutServiceLocation()).isEqualTo(SINGLE_LOGOUT_URL); + assertThat(found.getSingleLogoutServiceResponseLocation()).isEqualTo(SINGLE_LOGOUT_RESPONSE_URL); + assertThat(found.getSingleLogoutServiceBinding().getUrn()).isEqualTo(SINGLE_LOGOUT_BINDING); + assertThat(found.getSigningAlgorithms()).contains(SIGNING_ALGORITHMS.get(0)); + assertThat(found.getVerificationX509Credentials()).hasSize(1); + assertThat(found.getEncryptionX509Credentials()).hasSize(1); + } + + @Test + void findByEntityIdWhenNotExists() { + AssertingPartyMetadata found = this.repository.findByEntityId("non-existent-entity-id"); + assertThat(found).isNull(); + } + + @Test + void iterator() throws IOException { + this.jdbcOperations.update(SAVE_SQL, ENTITY_ID, SINGLE_SIGNON_URL, SINGLE_SIGNON_BINDING, + SINGLE_SIGNON_SIGN_REQUEST, this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, + SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); + + this.jdbcOperations.update(SAVE_SQL, "https://localhost/simplesaml2/saml2/idp/metadata.php", SINGLE_SIGNON_URL, + SINGLE_SIGNON_BINDING, SINGLE_SIGNON_SIGN_REQUEST, + this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), + this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, + SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); + + Iterator iterator = this.repository.iterator(); + AssertingPartyMetadata first = iterator.next(); + assertThat(first).isNotNull(); + AssertingPartyMetadata second = iterator.next(); + assertThat(second).isNotNull(); + assertThat(iterator.hasNext()).isFalse(); + } + + private static EmbeddedDatabase createDb() { + return createDb(SCHEMA_SQL_RESOURCE); + } + + private static EmbeddedDatabase createDb(String schema) { + // @formatter:off + return new EmbeddedDatabaseBuilder() + .generateUniqueName(true) + .setType(EmbeddedDatabaseType.HSQL) + .setScriptEncoding("UTF-8") + .addScript(schema) + .build(); + // @formatter:on + } + + private X509Certificate loadCertificate(String path) { + try (InputStream is = new ClassPathResource(path).getInputStream()) { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) factory.generateCertificate(is); + } + catch (Exception ex) { + throw new RuntimeException("Error loading certificate from " + path, ex); + } + } + + private Collection asCredentials(X509Certificate certificate) { + return List.of(new Saml2X509Credential(certificate, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION, + Saml2X509Credential.Saml2X509CredentialType.VERIFICATION)); + } + +} diff --git a/saml2/saml2-service-provider/src/test/resources/rsa.crt b/saml2/saml2-service-provider/src/test/resources/rsa.crt new file mode 100644 index 0000000000..aa147065de --- /dev/null +++ b/saml2/saml2-service-provider/src/test/resources/rsa.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1zCCAr+gAwIBAgIUCzQeKBMTO0iHVW3iKmZC41haqCowDQYJKoZIhvcNAQEL +BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI +Q2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55 +U2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MjAwODI5MDNa +Fw0zMzA5MTcwODI5MDNaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h +bWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG +A1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUfi4aaCotJZX6OSDjv6fxCCfc +ihSs91Z/mmN+yc1fsxVSs53SIbqUuo+Wzhv34kp8I/r03P9LWVTkFPbeDxAl75Oa +PGggxK55US0Zfy9Hj1BwWIKV3330N61emID1GDEtFKL4yJbJdreQXnIXTBL2o76V +nuV/tYozyZnb07IQ1WhUm5WDxgzM0yFudMynTczCBeZHfvharDtB8PFFhCZXW2/9 +TZVVfW4oOML8EAX3hvnvYBlFl/foxXekZSwq/odOkmWCZavT2+0sburHUlOnPGUh +Qj4tHwpMRczp7VX4ptV1D2UrxsK/2B+s9FK2QSLKQ9JzAYJ6WxQjHcvET9jvAgMB +AAGjUzBRMB0GA1UdDgQWBBQjDr/1E/01pfLPD8uWF7gbaYL0TTAfBgNVHSMEGDAW +gBQjDr/1E/01pfLPD8uWF7gbaYL0TTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQAGjUuec0+0XNMCRDKZslbImdCAVsKsEWk6NpnUViDFAxL+KQuC +NW131UeHb9SCzMqRwrY4QI3nAwJQCmilL/hFM3ss4acn3WHu1yci/iKPUKeL1ec5 +kCFUmqX1NpTiVaytZ/9TKEr69SMVqNfQiuW5U1bIIYTqK8xo46WpM6YNNHO3eJK6 +NH0MW79Wx5ryi4i4C6afqYbVbx7tqcmy8CFeNxgZ0bFQ87SiwYXIj77b6sVYbu32 +doykBQgSHLcagWASPQ73m73CWUgo+7+EqSKIQqORbgmTLPmOUh99gFIx7jmjTyHm +NBszx1ZVWuIv3mWmp626Kncyc+LLM9tvgymx +-----END CERTIFICATE----- From e2e42a5580bee84203ad9e1448269be91620dde2 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:45:51 -0600 Subject: [PATCH 327/504] Fix Checkstyle Issue gh-16012 --- ...AssertingPartyMetadataRepositoryTests.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java index c734bcb236..e8a76ee335 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.security.saml2.provider.service.registration; import java.io.IOException; @@ -62,7 +78,7 @@ class JdbcAssertingPartyMetadataRepositoryTests { private final Serializer serializer = new DefaultSerializer(); @BeforeEach - public void setUp() throws Exception { + void setUp() { this.db = createDb(); this.jdbcOperations = new JdbcTemplate(this.db); this.repository = new JdbcAssertingPartyMetadataRepository(this.jdbcOperations); @@ -70,7 +86,7 @@ class JdbcAssertingPartyMetadataRepositoryTests { } @AfterEach - public void tearDown() { + void tearDown() { this.db.shutdown(); } From 2bd05128ec614243f563a70fe0b6c09e726a29be Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:44:19 -0600 Subject: [PATCH 328/504] Add JdbcAssertingPartyMetadataRepository#save Issue gh-16012 Co-Authored-By: chao.wang --- .../JdbcAssertingPartyMetadataRepository.java | 78 ++++++++++++ ...AssertingPartyMetadataRepositoryTests.java | 120 ++++++------------ 2 files changed, 117 insertions(+), 81 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java index 620e6bdf2e..88f4a59a71 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java @@ -19,16 +19,20 @@ package org.springframework.security.saml2.provider.service.registration; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.log.LogMessage; import org.springframework.core.serializer.DefaultDeserializer; +import org.springframework.core.serializer.DefaultSerializer; import org.springframework.core.serializer.Deserializer; +import org.springframework.core.serializer.Serializer; import org.springframework.jdbc.core.ArgumentPreparedStatementSetter; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.PreparedStatementSetter; @@ -37,6 +41,7 @@ import org.springframework.jdbc.core.SqlParameterValue; import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; import org.springframework.util.Assert; +import org.springframework.util.function.ThrowingFunction; /** * A JDBC implementation of {@link AssertingPartyMetadataRepository}. @@ -51,6 +56,8 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart private RowMapper assertingPartyMetadataRowMapper = new AssertingPartyMetadataRowMapper( ResultSet::getBytes); + private final AssertingPartyMetadataParametersMapper assertingPartyMetadataParametersMapper = new AssertingPartyMetadataParametersMapper(); + // @formatter:off static final String COLUMN_NAMES = "entity_id, " + "singlesignon_url, " @@ -77,6 +84,25 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart + " FROM " + TABLE_NAME; // @formatter:on + // @formatter:off + private static final String SAVE_CREDENTIAL_RECORD_SQL = "INSERT INTO " + TABLE_NAME + + " (" + COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + // @formatter:on + + // @formatter:off + private static final String UPDATE_CREDENTIAL_RECORD_SQL = "UPDATE " + TABLE_NAME + + " SET singlesignon_url = ?, " + + "singlesignon_binding = ?, " + + "singlesignon_sign_request = ?, " + + "signing_algorithms = ?, " + + "verification_credentials = ?, " + + "encryption_credentials = ?, " + + "singlelogout_url = ?, " + + "singlelogout_response_url = ?, " + + "singlelogout_binding = ?" + + " WHERE " + ENTITY_ID_FILTER; + // @formatter:on + /** * Constructs a {@code JdbcRelyingPartyRegistrationRepository} using the provided * parameters. @@ -116,6 +142,30 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart return result.iterator(); } + /** + * Persist this {@link AssertingPartyMetadata} + * @param metadata the metadata to persist + */ + public void save(AssertingPartyMetadata metadata) { + Assert.notNull(metadata, "metadata cannot be null"); + int rows = updateCredentialRecord(metadata); + if (rows == 0) { + insertCredentialRecord(metadata); + } + } + + private void insertCredentialRecord(AssertingPartyMetadata metadata) { + List parameters = this.assertingPartyMetadataParametersMapper.apply(metadata); + this.jdbcOperations.update(SAVE_CREDENTIAL_RECORD_SQL, parameters.toArray()); + } + + private int updateCredentialRecord(AssertingPartyMetadata metadata) { + List parameters = this.assertingPartyMetadataParametersMapper.apply(metadata); + SqlParameterValue credentialId = parameters.remove(0); + parameters.add(credentialId); + return this.jdbcOperations.update(UPDATE_CREDENTIAL_RECORD_SQL, parameters.toArray()); + } + /** * The default {@link RowMapper} that maps the current row in * {@code java.sql.ResultSet} to {@link AssertingPartyMetadata}. @@ -181,6 +231,34 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart } + private static class AssertingPartyMetadataParametersMapper + implements Function> { + + private final Serializer serializer = new DefaultSerializer(); + + @Override + public List apply(AssertingPartyMetadata record) { + List parameters = new ArrayList<>(); + + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getEntityId())); + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleSignOnServiceLocation())); + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleSignOnServiceBinding().getUrn())); + parameters.add(new SqlParameterValue(Types.BOOLEAN, record.getWantAuthnRequestsSigned())); + ThrowingFunction, byte[]> algorithms = this.serializer::serializeToByteArray; + parameters.add(new SqlParameterValue(Types.BLOB, algorithms.apply(record.getSigningAlgorithms()))); + ThrowingFunction, byte[]> credentials = this.serializer::serializeToByteArray; + parameters + .add(new SqlParameterValue(Types.BLOB, credentials.apply(record.getVerificationX509Credentials()))); + parameters.add(new SqlParameterValue(Types.BLOB, credentials.apply(record.getEncryptionX509Credentials()))); + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleLogoutServiceLocation())); + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleLogoutServiceResponseLocation())); + parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleLogoutServiceBinding().getUrn())); + + return parameters; + } + + } + private interface GetBytes { byte[] getBytes(ResultSet rs, String columnName) throws SQLException; diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java index e8a76ee335..785e4a12f3 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java @@ -16,27 +16,17 @@ package org.springframework.security.saml2.provider.service.registration; -import java.io.IOException; -import java.io.InputStream; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Collection; import java.util.Iterator; -import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.serializer.DefaultSerializer; -import org.springframework.core.serializer.Serializer; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.security.saml2.core.Saml2X509Credential; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -48,41 +38,21 @@ class JdbcAssertingPartyMetadataRepositoryTests { private static final String SCHEMA_SQL_RESOURCE = "org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql"; - private static final String SAVE_SQL = "INSERT INTO saml2_asserting_party_metadata (" - + JdbcAssertingPartyMetadataRepository.COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - - private static final String ENTITY_ID = "https://localhost/simplesaml/saml2/idp/metadata.php"; - - private static final String SINGLE_SIGNON_URL = "https://localhost/SSO"; - - private static final String SINGLE_SIGNON_BINDING = Saml2MessageBinding.REDIRECT.getUrn(); - - private static final boolean SINGLE_SIGNON_SIGN_REQUEST = false; - - private static final String SINGLE_LOGOUT_URL = "https://localhost/SLO"; - - private static final String SINGLE_LOGOUT_RESPONSE_URL = "https://localhost/SLO/response"; - - private static final String SINGLE_LOGOUT_BINDING = Saml2MessageBinding.REDIRECT.getUrn(); - - private static final List SIGNING_ALGORITHMS = List.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"); - - private X509Certificate certificate; - private EmbeddedDatabase db; private JdbcAssertingPartyMetadataRepository repository; private JdbcOperations jdbcOperations; - private final Serializer serializer = new DefaultSerializer(); + private final AssertingPartyMetadata metadata = TestRelyingPartyRegistrations.full() + .build() + .getAssertingPartyMetadata(); @BeforeEach void setUp() { this.db = createDb(); this.jdbcOperations = new JdbcTemplate(this.db); this.repository = new JdbcAssertingPartyMetadataRepository(this.jdbcOperations); - this.certificate = loadCertificate("rsa.crt"); } @AfterEach @@ -109,26 +79,12 @@ class JdbcAssertingPartyMetadataRepositoryTests { } @Test - void findByEntityId() throws IOException { - this.jdbcOperations.update(SAVE_SQL, ENTITY_ID, SINGLE_SIGNON_URL, SINGLE_SIGNON_BINDING, - SINGLE_SIGNON_SIGN_REQUEST, this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, - SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); + void findByEntityId() { + this.repository.save(this.metadata); - AssertingPartyMetadata found = this.repository.findByEntityId(ENTITY_ID); + AssertingPartyMetadata found = this.repository.findByEntityId(this.metadata.getEntityId()); - assertThat(found).isNotNull(); - assertThat(found.getEntityId()).isEqualTo(ENTITY_ID); - assertThat(found.getSingleSignOnServiceLocation()).isEqualTo(SINGLE_SIGNON_URL); - assertThat(found.getSingleSignOnServiceBinding().getUrn()).isEqualTo(SINGLE_SIGNON_BINDING); - assertThat(found.getWantAuthnRequestsSigned()).isEqualTo(SINGLE_SIGNON_SIGN_REQUEST); - assertThat(found.getSingleLogoutServiceLocation()).isEqualTo(SINGLE_LOGOUT_URL); - assertThat(found.getSingleLogoutServiceResponseLocation()).isEqualTo(SINGLE_LOGOUT_RESPONSE_URL); - assertThat(found.getSingleLogoutServiceBinding().getUrn()).isEqualTo(SINGLE_LOGOUT_BINDING); - assertThat(found.getSigningAlgorithms()).contains(SIGNING_ALGORITHMS.get(0)); - assertThat(found.getVerificationX509Credentials()).hasSize(1); - assertThat(found.getEncryptionX509Credentials()).hasSize(1); + assertAssertingPartyEquals(found, this.metadata); } @Test @@ -138,28 +94,30 @@ class JdbcAssertingPartyMetadataRepositoryTests { } @Test - void iterator() throws IOException { - this.jdbcOperations.update(SAVE_SQL, ENTITY_ID, SINGLE_SIGNON_URL, SINGLE_SIGNON_BINDING, - SINGLE_SIGNON_SIGN_REQUEST, this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, - SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); - - this.jdbcOperations.update(SAVE_SQL, "https://localhost/simplesaml2/saml2/idp/metadata.php", SINGLE_SIGNON_URL, - SINGLE_SIGNON_BINDING, SINGLE_SIGNON_SIGN_REQUEST, - this.serializer.serializeToByteArray(SIGNING_ALGORITHMS), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), - this.serializer.serializeToByteArray(asCredentials(this.certificate)), SINGLE_LOGOUT_URL, - SINGLE_LOGOUT_RESPONSE_URL, SINGLE_LOGOUT_BINDING); + void iterator() { + AssertingPartyMetadata second = RelyingPartyRegistration.withAssertingPartyMetadata(this.metadata) + .assertingPartyMetadata((a) -> a.entityId("https://example.org/idp")) + .build() + .getAssertingPartyMetadata(); + this.repository.save(this.metadata); + this.repository.save(second); Iterator iterator = this.repository.iterator(); - AssertingPartyMetadata first = iterator.next(); - assertThat(first).isNotNull(); - AssertingPartyMetadata second = iterator.next(); - assertThat(second).isNotNull(); + + assertAssertingPartyEquals(iterator.next(), this.metadata); + assertAssertingPartyEquals(iterator.next(), second); assertThat(iterator.hasNext()).isFalse(); } + @Test + void saveWhenExistingThenUpdates() { + this.repository.save(this.metadata); + boolean existing = this.metadata.getWantAuthnRequestsSigned(); + this.repository.save(this.metadata.mutate().wantAuthnRequestsSigned(!existing).build()); + boolean updated = this.repository.findByEntityId(this.metadata.getEntityId()).getWantAuthnRequestsSigned(); + assertThat(existing).isNotEqualTo(updated); + } + private static EmbeddedDatabase createDb() { return createDb(SCHEMA_SQL_RESOURCE); } @@ -175,19 +133,19 @@ class JdbcAssertingPartyMetadataRepositoryTests { // @formatter:on } - private X509Certificate loadCertificate(String path) { - try (InputStream is = new ClassPathResource(path).getInputStream()) { - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - return (X509Certificate) factory.generateCertificate(is); - } - catch (Exception ex) { - throw new RuntimeException("Error loading certificate from " + path, ex); - } - } - - private Collection asCredentials(X509Certificate certificate) { - return List.of(new Saml2X509Credential(certificate, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION, - Saml2X509Credential.Saml2X509CredentialType.VERIFICATION)); + private void assertAssertingPartyEquals(AssertingPartyMetadata found, AssertingPartyMetadata expected) { + assertThat(found).isNotNull(); + assertThat(found.getEntityId()).isEqualTo(expected.getEntityId()); + assertThat(found.getSingleSignOnServiceLocation()).isEqualTo(expected.getSingleSignOnServiceLocation()); + assertThat(found.getSingleSignOnServiceBinding()).isEqualTo(expected.getSingleSignOnServiceBinding()); + assertThat(found.getWantAuthnRequestsSigned()).isEqualTo(expected.getWantAuthnRequestsSigned()); + assertThat(found.getSingleLogoutServiceLocation()).isEqualTo(expected.getSingleLogoutServiceLocation()); + assertThat(found.getSingleLogoutServiceResponseLocation()) + .isEqualTo(expected.getSingleLogoutServiceResponseLocation()); + assertThat(found.getSingleLogoutServiceBinding()).isEqualTo(expected.getSingleLogoutServiceBinding()); + assertThat(found.getSigningAlgorithms()).containsAll(expected.getSigningAlgorithms()); + assertThat(found.getVerificationX509Credentials()).containsAll(expected.getVerificationX509Credentials()); + assertThat(found.getEncryptionX509Credentials()).containsAll(expected.getEncryptionX509Credentials()); } } From e8f920e0eeafff1af55427c13db054a3b6b13830 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:01:51 -0600 Subject: [PATCH 329/504] Polish JdbcAssertingPartyMetadataRepository - Remove GetBytes since it's not used yet - Remove customizable RowMapper since this can be added later - Change signing_algorithms to be a String since the conversion strategy is simple - Standardize test names - Simplify conversion of credentials using ThrowingFunction - Change column names to match RelyingPartyRegistration field names Issue gh-16012 --- .../JdbcAssertingPartyMetadataRepository.java | 129 ++++++------------ ...serting-party-metadata-schema-postgres.sql | 20 +-- .../saml2-asserting-party-metadata-schema.sql | 20 +-- ...AssertingPartyMetadataRepositoryTests.java | 11 +- 4 files changed, 63 insertions(+), 117 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java index 88f4a59a71..9cf3234ea9 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java @@ -20,15 +20,13 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.function.Function; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.log.LogMessage; import org.springframework.core.serializer.DefaultDeserializer; import org.springframework.core.serializer.DefaultSerializer; import org.springframework.core.serializer.Deserializer; @@ -53,22 +51,22 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart private final JdbcOperations jdbcOperations; - private RowMapper assertingPartyMetadataRowMapper = new AssertingPartyMetadataRowMapper( - ResultSet::getBytes); + private final RowMapper assertingPartyMetadataRowMapper = new AssertingPartyMetadataRowMapper(); private final AssertingPartyMetadataParametersMapper assertingPartyMetadataParametersMapper = new AssertingPartyMetadataParametersMapper(); // @formatter:off - static final String COLUMN_NAMES = "entity_id, " - + "singlesignon_url, " - + "singlesignon_binding, " - + "singlesignon_sign_request, " - + "signing_algorithms, " - + "verification_credentials, " - + "encryption_credentials, " - + "singlelogout_url, " - + "singlelogout_response_url, " - + "singlelogout_binding"; + static final String[] COLUMN_NAMES = { "entity_id", + "single_sign_on_service_location", + "single_sign_on_service_binding", + "want_authn_requests_signed", + "signing_algorithms", + "verification_credentials", + "encryption_credentials", + "single_logout_service_location", + "single_logout_service_response_location", + "single_logout_service_binding" }; + // @formatter:on private static final String TABLE_NAME = "saml2_asserting_party_metadata"; @@ -76,30 +74,23 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart private static final String ENTITY_ID_FILTER = "entity_id = ?"; // @formatter:off - private static final String LOAD_BY_ID_SQL = "SELECT " + COLUMN_NAMES + private static final String LOAD_BY_ID_SQL = "SELECT " + String.join(",", COLUMN_NAMES) + " FROM " + TABLE_NAME + " WHERE " + ENTITY_ID_FILTER; - private static final String LOAD_ALL_SQL = "SELECT " + COLUMN_NAMES + private static final String LOAD_ALL_SQL = "SELECT " + String.join(",", COLUMN_NAMES) + " FROM " + TABLE_NAME; // @formatter:on // @formatter:off private static final String SAVE_CREDENTIAL_RECORD_SQL = "INSERT INTO " + TABLE_NAME - + " (" + COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + " (" + String.join(",", COLUMN_NAMES) + ") VALUES (" + String.join(",", Collections.nCopies(COLUMN_NAMES.length, "?")) + ")"; // @formatter:on // @formatter:off private static final String UPDATE_CREDENTIAL_RECORD_SQL = "UPDATE " + TABLE_NAME - + " SET singlesignon_url = ?, " - + "singlesignon_binding = ?, " - + "singlesignon_sign_request = ?, " - + "signing_algorithms = ?, " - + "verification_credentials = ?, " - + "encryption_credentials = ?, " - + "singlelogout_url = ?, " - + "singlelogout_response_url = ?, " - + "singlelogout_binding = ?" + + " SET " + String.join(" = ?,", Arrays.copyOfRange(COLUMN_NAMES, 1, COLUMN_NAMES.length)) + + " = ?" + " WHERE " + ENTITY_ID_FILTER; // @formatter:on @@ -113,18 +104,6 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart this.jdbcOperations = jdbcOperations; } - /** - * Sets the {@link RowMapper} used for mapping the current row in - * {@code java.sql.ResultSet} to {@link AssertingPartyMetadata}. The default is - * {@link AssertingPartyMetadataRowMapper}. - * @param assertingPartyMetadataRowMapper the {@link RowMapper} used for mapping the - * current row in {@code java.sql.ResultSet} to {@link AssertingPartyMetadata} - */ - public void setAssertingPartyMetadataRowMapper(RowMapper assertingPartyMetadataRowMapper) { - Assert.notNull(assertingPartyMetadataRowMapper, "assertingPartyMetadataRowMapper cannot be null"); - this.assertingPartyMetadataRowMapper = assertingPartyMetadataRowMapper; - } - @Override public AssertingPartyMetadata findByEntityId(String entityId) { Assert.hasText(entityId, "entityId cannot be empty"); @@ -172,52 +151,26 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart */ private static final class AssertingPartyMetadataRowMapper implements RowMapper { - private final Log logger = LogFactory.getLog(AssertingPartyMetadataRowMapper.class); - private final Deserializer deserializer = new DefaultDeserializer(); - private final GetBytes getBytes; - - AssertingPartyMetadataRowMapper(GetBytes getBytes) { - this.getBytes = getBytes; - } - @Override public AssertingPartyMetadata mapRow(ResultSet rs, int rowNum) throws SQLException { - String entityId = rs.getString("entity_id"); - String singleSignOnUrl = rs.getString("singlesignon_url"); - Saml2MessageBinding singleSignOnBinding = Saml2MessageBinding.from(rs.getString("singlesignon_binding")); - boolean singleSignOnSignRequest = rs.getBoolean("singlesignon_sign_request"); - String singleLogoutUrl = rs.getString("singlelogout_url"); - String singleLogoutResponseUrl = rs.getString("singlelogout_response_url"); - Saml2MessageBinding singleLogoutBinding = Saml2MessageBinding.from(rs.getString("singlelogout_binding")); - byte[] signingAlgorithmsBytes = this.getBytes.getBytes(rs, "signing_algorithms"); - byte[] verificationCredentialsBytes = this.getBytes.getBytes(rs, "verification_credentials"); - byte[] encryptionCredentialsBytes = this.getBytes.getBytes(rs, "encryption_credentials"); - + String entityId = rs.getString(COLUMN_NAMES[0]); + String singleSignOnUrl = rs.getString(COLUMN_NAMES[1]); + Saml2MessageBinding singleSignOnBinding = Saml2MessageBinding.from(rs.getString(COLUMN_NAMES[2])); + boolean singleSignOnSignRequest = rs.getBoolean(COLUMN_NAMES[3]); + List algorithms = List.of(rs.getString(COLUMN_NAMES[4]).split(",")); + byte[] verificationCredentialsBytes = rs.getBytes(COLUMN_NAMES[5]); + byte[] encryptionCredentialsBytes = rs.getBytes(COLUMN_NAMES[6]); + ThrowingFunction> credentials = ( + bytes) -> (Collection) this.deserializer.deserializeFromByteArray(bytes); AssertingPartyMetadata.Builder builder = new AssertingPartyDetails.Builder(); - try { - if (signingAlgorithmsBytes != null) { - List signingAlgorithms = (List) this.deserializer - .deserializeFromByteArray(signingAlgorithmsBytes); - builder.signingAlgorithms((algorithms) -> algorithms.addAll(signingAlgorithms)); - } - if (verificationCredentialsBytes != null) { - Collection verificationCredentials = (Collection) this.deserializer - .deserializeFromByteArray(verificationCredentialsBytes); - builder.verificationX509Credentials((credentials) -> credentials.addAll(verificationCredentials)); - } - if (encryptionCredentialsBytes != null) { - Collection encryptionCredentials = (Collection) this.deserializer - .deserializeFromByteArray(encryptionCredentialsBytes); - builder.encryptionX509Credentials((credentials) -> credentials.addAll(encryptionCredentials)); - } - } - catch (Exception ex) { - this.logger.debug(LogMessage.format("Parsing serialized credentials for entity %s failed", entityId), - ex); - return null; - } + Collection verificationCredentials = credentials.apply(verificationCredentialsBytes); + Collection encryptionCredentials = (encryptionCredentialsBytes != null) + ? credentials.apply(encryptionCredentialsBytes) : List.of(); + String singleLogoutUrl = rs.getString(COLUMN_NAMES[7]); + String singleLogoutResponseUrl = rs.getString(COLUMN_NAMES[8]); + Saml2MessageBinding singleLogoutBinding = Saml2MessageBinding.from(rs.getString(COLUMN_NAMES[9])); builder.entityId(entityId) .wantAuthnRequestsSigned(singleSignOnSignRequest) @@ -225,7 +178,10 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart .singleSignOnServiceBinding(singleSignOnBinding) .singleLogoutServiceLocation(singleLogoutUrl) .singleLogoutServiceBinding(singleLogoutBinding) - .singleLogoutServiceResponseLocation(singleLogoutResponseUrl); + .singleLogoutServiceResponseLocation(singleLogoutResponseUrl) + .signingAlgorithms((a) -> a.addAll(algorithms)) + .verificationX509Credentials((c) -> c.addAll(verificationCredentials)) + .encryptionX509Credentials((c) -> c.addAll(encryptionCredentials)); return builder.build(); } @@ -244,8 +200,7 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleSignOnServiceLocation())); parameters.add(new SqlParameterValue(Types.VARCHAR, record.getSingleSignOnServiceBinding().getUrn())); parameters.add(new SqlParameterValue(Types.BOOLEAN, record.getWantAuthnRequestsSigned())); - ThrowingFunction, byte[]> algorithms = this.serializer::serializeToByteArray; - parameters.add(new SqlParameterValue(Types.BLOB, algorithms.apply(record.getSigningAlgorithms()))); + parameters.add(new SqlParameterValue(Types.BLOB, String.join(",", record.getSigningAlgorithms()))); ThrowingFunction, byte[]> credentials = this.serializer::serializeToByteArray; parameters .add(new SqlParameterValue(Types.BLOB, credentials.apply(record.getVerificationX509Credentials()))); @@ -259,10 +214,4 @@ public final class JdbcAssertingPartyMetadataRepository implements AssertingPart } - private interface GetBytes { - - byte[] getBytes(ResultSet rs, String columnName) throws SQLException; - - } - } diff --git a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql index ffa047fe7b..130e141f59 100644 --- a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql +++ b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema-postgres.sql @@ -1,14 +1,14 @@ CREATE TABLE saml2_asserting_party_metadata ( - entity_id VARCHAR(1000) NOT NULL, - singlesignon_url VARCHAR(1000) NOT NULL, - singlesignon_binding VARCHAR(100), - singlesignon_sign_request boolean, - signing_algorithms BYTEA, - verification_credentials BYTEA NOT NULL, - encryption_credentials BYTEA, - singlelogout_url VARCHAR(1000), - singlelogout_response_url VARCHAR(1000), - singlelogout_binding VARCHAR(100), + entity_id VARCHAR(1000) NOT NULL, + single_sign_on_service_location VARCHAR(1000) NOT NULL, + single_sign_on_service_binding VARCHAR(100), + want_authn_requests_signed boolean, + signing_algorithms BYTEA, + verification_credentials BYTEA NOT NULL, + encryption_credentials BYTEA, + single_logout_service_location VARCHAR(1000), + single_logout_service_response_location VARCHAR(1000), + single_logout_service_binding VARCHAR(100), PRIMARY KEY (entity_id) ); diff --git a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql index 2fd6cb8cdf..5c9b6a4826 100644 --- a/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql +++ b/saml2/saml2-service-provider/src/main/resources/org/springframework/security/saml2/saml2-asserting-party-metadata-schema.sql @@ -1,14 +1,14 @@ CREATE TABLE saml2_asserting_party_metadata ( - entity_id VARCHAR(1000) NOT NULL, - singlesignon_url VARCHAR(1000) NOT NULL, - singlesignon_binding VARCHAR(100), - singlesignon_sign_request boolean, - signing_algorithms blob, - verification_credentials blob NOT NULL, - encryption_credentials blob, - singlelogout_url VARCHAR(1000), - singlelogout_response_url VARCHAR(1000), - singlelogout_binding VARCHAR(100), + entity_id VARCHAR(1000) NOT NULL, + single_sign_on_service_location VARCHAR(1000) NOT NULL, + single_sign_on_service_binding VARCHAR(100), + want_authn_requests_signed boolean, + signing_algorithms VARCHAR(256) NOT NULL, + verification_credentials blob NOT NULL, + encryption_credentials blob, + single_logout_service_location VARCHAR(1000), + single_logout_service_response_location VARCHAR(1000), + single_logout_service_binding VARCHAR(100), PRIMARY KEY (entity_id) ); diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java index 785e4a12f3..56f871a664 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepositoryTests.java @@ -79,7 +79,7 @@ class JdbcAssertingPartyMetadataRepositoryTests { } @Test - void findByEntityId() { + void findByEntityIdWhenEntityPresentThenReturns() { this.repository.save(this.metadata); AssertingPartyMetadata found = this.repository.findByEntityId(this.metadata.getEntityId()); @@ -88,17 +88,14 @@ class JdbcAssertingPartyMetadataRepositoryTests { } @Test - void findByEntityIdWhenNotExists() { + void findByEntityIdWhenNotExistsThenNull() { AssertingPartyMetadata found = this.repository.findByEntityId("non-existent-entity-id"); assertThat(found).isNull(); } @Test - void iterator() { - AssertingPartyMetadata second = RelyingPartyRegistration.withAssertingPartyMetadata(this.metadata) - .assertingPartyMetadata((a) -> a.entityId("https://example.org/idp")) - .build() - .getAssertingPartyMetadata(); + void iteratorWhenEnitiesExistThenContains() { + AssertingPartyMetadata second = this.metadata.mutate().entityId("https://example.org/idp").build(); this.repository.save(this.metadata); this.repository.save(second); From aba437d4698c0b30559021e3f41b85607fee8ce0 Mon Sep 17 00:00:00 2001 From: Max Batischev Date: Fri, 16 May 2025 14:07:10 +0300 Subject: [PATCH 330/504] Add Support SubjectX500PrincipalExtractor Closes gh-16980 Signed-off-by: Max Batischev --- .../web/configurers/X509Configurer.java | 28 +++++- .../http/AuthenticationConfigBuilder.java | 16 +++- .../config/web/server/ServerHttpSecurity.java | 12 +-- .../security/config/spring-security-7.0.rnc | 3 + .../security/config/spring-security-7.0.xsd | 6 ++ .../web/configurers/X509ConfigurerTests.java | 39 +++++++- config/src/test/resources/max.cer | 17 ++++ .../servlet/appendix/namespace/http.adoc | 3 + .../x509/SubjectDnX509PrincipalExtractor.java | 6 +- .../x509/SubjectX500PrincipalExtractor.java | 88 +++++++++++++++++++ .../x509/X509AuthenticationFilter.java | 4 +- .../SubjectX500PrincipalExtractorTests.java | 66 ++++++++++++++ 12 files changed, 276 insertions(+), 12 deletions(-) create mode 100644 config/src/test/resources/max.cer create mode 100644 web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java create mode 100644 web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractorTests.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java index a3818e2a9a..b9b766a14d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails; import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; @@ -74,6 +75,7 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR * * @author Rob Winch * @author Ngoc Nhan + * @author Max Batischev * @since 3.2 */ public final class X509Configurer> @@ -161,14 +163,38 @@ public final class X509Configurer> * @param subjectPrincipalRegex the regex to extract the user principal from the * certificate (i.e. "CN=(.*?)(?:,|$)"). * @return the {@link X509Configurer} for further customizations + * @deprecated Please use {{@link #extractPrincipalNameFromEmail(boolean)}} instead */ + @Deprecated public X509Configurer subjectPrincipalRegex(String subjectPrincipalRegex) { + if (this.x509PrincipalExtractor instanceof SubjectX500PrincipalExtractor) { + throw new IllegalStateException( + "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " + + "Please use one or the other."); + } SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor(); principalExtractor.setSubjectDnRegex(subjectPrincipalRegex); this.x509PrincipalExtractor = principalExtractor; return this; } + /** + * If true then DN will be extracted from EMAIlADDRESS, defaults to {@code false} + * @param extractPrincipalNameFromEmail whether to extract DN from EMAIlADDRESS + * @since 7.0 + */ + public X509Configurer extractPrincipalNameFromEmail(boolean extractPrincipalNameFromEmail) { + if (this.x509PrincipalExtractor instanceof SubjectDnX509PrincipalExtractor) { + throw new IllegalStateException( + "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " + + "Please use one or the other."); + } + SubjectX500PrincipalExtractor extractor = new SubjectX500PrincipalExtractor(); + extractor.setExtractPrincipalNameFromEmail(extractPrincipalNameFromEmail); + this.x509PrincipalExtractor = extractor; + return this; + } + @Override public void init(H http) { PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider(); diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java index f997e5fa5e..9b6ee210ac 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,7 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedG import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource; import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter; @@ -522,12 +523,25 @@ final class AuthenticationConfigBuilder { filterBuilder.addPropertyValue("securityContextHolderStrategy", authenticationFilterSecurityContextHolderStrategyRef); String regex = x509Elt.getAttribute("subject-principal-regex"); + String extractPrincipalNameFromEmail = x509Elt.getAttribute("extract-principal-name-from-email"); + if (StringUtils.hasText(regex) && StringUtils.hasText(extractPrincipalNameFromEmail)) { + throw new IllegalStateException( + "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " + + "Please use one or the other."); + } if (StringUtils.hasText(regex)) { BeanDefinitionBuilder extractor = BeanDefinitionBuilder .rootBeanDefinition(SubjectDnX509PrincipalExtractor.class); extractor.addPropertyValue("subjectDnRegex", regex); filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); } + if (StringUtils.hasText(extractPrincipalNameFromEmail)) { + BeanDefinitionBuilder extractor = BeanDefinitionBuilder + .rootBeanDefinition(SubjectX500PrincipalExtractor.class); + extractor.addPropertyValue("extractPrincipalNameFromEmail", + Boolean.parseBoolean(extractPrincipalNameFromEmail)); + filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); + } injectAuthenticationDetailsSource(x509Elt, filterBuilder); filter = (RootBeanDefinition) filterBuilder.getBeanDefinition(); createPrauthEntryPoint(x509Elt); diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index a4063fced4..f0760bc64e 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -119,7 +119,7 @@ import org.springframework.security.oauth2.server.resource.web.server.BearerToke import org.springframework.security.oauth2.server.resource.web.server.authentication.ServerBearerTokenAuthenticationConverter; import org.springframework.security.web.PortMapper; import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor; import org.springframework.security.web.server.DefaultServerRedirectStrategy; import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint; @@ -944,8 +944,8 @@ public class ServerHttpSecurity { * } * * - * Note that if extractor is not specified, {@link SubjectDnX509PrincipalExtractor} - * will be used. If authenticationManager is not specified, + * Note that if extractor is not specified, {@link SubjectX500PrincipalExtractor} will + * be used. If authenticationManager is not specified, * {@link ReactivePreAuthenticatedAuthenticationManager} will be used. * @return the {@link X509Spec} to customize * @since 5.2 @@ -979,8 +979,8 @@ public class ServerHttpSecurity { * } * * - * Note that if extractor is not specified, {@link SubjectDnX509PrincipalExtractor} - * will be used. If authenticationManager is not specified, + * Note that if extractor is not specified, {@link SubjectX500PrincipalExtractor} will + * be used. If authenticationManager is not specified, * {@link ReactivePreAuthenticatedAuthenticationManager} will be used. * @param x509Customizer the {@link Customizer} to provide more options for the * {@link X509Spec} @@ -4181,7 +4181,7 @@ public class ServerHttpSecurity { if (this.principalExtractor != null) { return this.principalExtractor; } - return new SubjectDnX509PrincipalExtractor(); + return new SubjectX500PrincipalExtractor(); } private ReactiveAuthenticationManager getAuthenticationManager() { diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc index bbf8622dfe..1236a2aec5 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -1053,6 +1053,9 @@ x509.attlist &= x509.attlist &= ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter attribute authentication-details-source-ref {xsd:token}? +x509.attlist &= + ## If true then DN will be extracted from EMAIlADDRESS + attribute extract-principal-name-from-email {xsd:token}? jee = ## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 2e3d6cf275..ed82f3468b 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -2917,6 +2917,12 @@ + + + If true then DN will be extracted from EMAIlADDRESS + + + diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java index 206c0b7ece..38983691e1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,6 +123,16 @@ public class X509ConfigurerTests { // @formatter:on } + @Test + public void x509WhenExtractPrincipalNameFromEmailIsTrueThenUsesEmailAddressToExtractPrincipal() throws Exception { + this.spring.register(EmailPrincipalConfig.class).autowire(); + X509Certificate certificate = loadCert("max.cer"); + // @formatter:off + this.mvc.perform(get("/").with(x509(certificate))) + .andExpect(authenticated().withUsername("maxbatischev@gmail.com")); + // @formatter:on + } + @Test public void x509WhenUserDetailsServiceNotConfiguredThenUsesBean() throws Exception { this.spring.register(UserDetailsServiceBeanConfig.class).autowire(); @@ -277,6 +287,33 @@ public class X509ConfigurerTests { } + @Configuration + @EnableWebSecurity + static class EmailPrincipalConfig { + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .x509((x509) -> + x509.extractPrincipalNameFromEmail(true) + ); + // @formatter:on + return http.build(); + } + + @Bean + UserDetailsService userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("maxbatischev@gmail.com") + .password("password") + .roles("USER", "ADMIN") + .build(); + return new InMemoryUserDetailsManager(user); + } + + } + @Configuration @EnableWebSecurity static class UserDetailsServiceBeanConfig { diff --git a/config/src/test/resources/max.cer b/config/src/test/resources/max.cer new file mode 100644 index 0000000000..bd79b1f096 --- /dev/null +++ b/config/src/test/resources/max.cer @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICojCCAgugAwIBAgIBADANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJydTEP +MA0GA1UECAwGTW9zY293MQ8wDQYDVQQKDAZTcHJpbmcxFjAUBgNVBAMMDU1heCBC +YXRpc2NoZXYxJTAjBgkqhkiG9w0BCQEWFm1heGJhdGlzY2hldkBnbWFpbC5jb20w +HhcNMjUwNTE0MTcyODM5WhcNMjYwNTE0MTcyODM5WjBuMQswCQYDVQQGEwJydTEP +MA0GA1UECAwGTW9zY293MQ8wDQYDVQQKDAZTcHJpbmcxFjAUBgNVBAMMDU1heCBC +YXRpc2NoZXYxJTAjBgkqhkiG9w0BCQEWFm1heGJhdGlzY2hldkBnbWFpbC5jb20w +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVZ2K/iOINeHZ4XAV3QmNRgS+iB +Vw0fW07uzYkCoSZU1lOBQE0k8+fdM2+X9AsgwfRCE3tUZquPApEKynB5V9Seh+bR +vc9aj7PunMyN+zjRU6X7/BL3VqLfrJLSc15bQaSN1phJ6NT+BTXPTuiPbXldnJLC +wVo6PView83yZ335AgMBAAGjUDBOMB0GA1UdDgQWBBQhyQfxL2ZYotcS8AmMJtli +2IRAMTAfBgNVHSMEGDAWgBQhyQfxL2ZYotcS8AmMJtli2IRAMTAMBgNVHRMEBTAD +AQH/MA0GCSqGSIb3DQEBDQUAA4GBAIIIJxpsTPtUEnePAqqgVFWDKC2CExhtCBYL +MjLSC+7E9OlfuuX1joAsD4Yv86k4Ox836D0KQtINtg3y6D8O+HSylhVg1xtOiK7l +ElXVRepB8GcX3vf9F58v9s++cSDvXf8vJu/O7nI4fv9C5SfUtMY4JPh/3MTsyl8O +tgxTKjvO +-----END CERTIFICATE----- diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 8979d5ad29..812706ae1d 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -2229,6 +2229,9 @@ Defines a regular expression which will be used to extract the username from the Allows a specific `UserDetailsService` to be used with X.509 in the case where multiple instances are configured. If not set, an attempt will be made to locate a suitable instance automatically and use that. +[[nsa-x509-extract-principal-name-from-email]] +* **extract-principal-name-from-email** +If true then DN will be extracted from EMAIlADDRESS. [[nsa-filter-chain-map]] == diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java index b690af59c0..ffa217d8d5 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.security.web.authentication.preauth.x509; +import java.security.Principal; import java.security.cert.X509Certificate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,7 +44,9 @@ import org.springframework.util.Assert; * "EMAILADDRESS=jimi@hendrix.org, CN=..." giving a user name "jimi@hendrix.org" * * @author Luke Taylor + * @deprecated Please use {@link SubjectX500PrincipalExtractor} instead */ +@Deprecated public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor, MessageSourceAware { protected final Log logger = LogFactory.getLog(getClass()); @@ -59,6 +62,7 @@ public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor, @Override public Object extractPrincipal(X509Certificate clientCert) { // String subjectDN = clientCert.getSubjectX500Principal().getName(); + Principal principal = clientCert.getSubjectDN(); String subjectDN = clientCert.getSubjectDN().getName(); this.logger.debug(LogMessage.format("Subject DN is '%s'", subjectDN)); Matcher matcher = this.subjectDnPattern.matcher(subjectDN); diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java new file mode 100644 index 0000000000..4b735c0528 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.authentication.preauth.x509; + +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.security.auth.x500.X500Principal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.core.log.LogMessage; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.SpringSecurityMessageSource; +import org.springframework.util.Assert; + +/** + * Obtains the principal from a certificate using RFC2253 and RFC1779 formats. By default, + * RFC2253 is used: DN is extracted from CN. If extractPrincipalNameFromEmail is true then + * format RFC1779 will be used: DN is extracted from EMAIlADDRESS. + * + * @author Max Batischev + * @since 7.0 + */ +public final class SubjectX500PrincipalExtractor implements X509PrincipalExtractor, MessageSourceAware { + + private final Log logger = LogFactory.getLog(getClass()); + + private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + + private boolean extractPrincipalNameFromEmail = false; + + private final Pattern cnSubjectDnPattern = Pattern.compile("CN=(.*?)(?:,|$)", Pattern.CASE_INSENSITIVE); + + private final Pattern emailSubjectDnPattern = Pattern.compile("OID.1.2.840.113549.1.9.1=(.*?)(?:,|$)", + Pattern.CASE_INSENSITIVE); + + @Override + public Object extractPrincipal(X509Certificate clientCert) { + Assert.notNull(clientCert, "clientCert cannot be null"); + X500Principal principal = clientCert.getSubjectX500Principal(); + String subjectDN = this.extractPrincipalNameFromEmail ? principal.getName("RFC1779") : principal.getName(); + this.logger.debug(LogMessage.format("Subject DN is '%s'", subjectDN)); + Matcher matcher = this.extractPrincipalNameFromEmail ? this.emailSubjectDnPattern.matcher(subjectDN) + : this.cnSubjectDnPattern.matcher(subjectDN); + if (!matcher.find()) { + throw new BadCredentialsException(this.messages.getMessage("SubjectX500PrincipalExtractor.noMatching", + new Object[] { subjectDN }, "No matching pattern was found in subject DN: {0}")); + } + String principalName = matcher.group(1); + this.logger.debug(LogMessage.format("Extracted Principal name is '%s'", principalName)); + return principalName; + } + + @Override + public void setMessageSource(MessageSource messageSource) { + Assert.notNull(messageSource, "messageSource cannot be null"); + this.messages = new MessageSourceAccessor(messageSource); + } + + /** + * If true then DN will be extracted from EMAIlADDRESS, defaults to {@code false} + * @param extractPrincipalNameFromEmail whether to extract DN from EMAIlADDRESS + */ + public void setExtractPrincipalNameFromEmail(boolean extractPrincipalNameFromEmail) { + this.extractPrincipalNameFromEmail = extractPrincipalNameFromEmail; + } + +} diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509AuthenticationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509AuthenticationFilter.java index c49cc6ab2f..02618d126d 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509AuthenticationFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509AuthenticationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen */ public class X509AuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter { - private X509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor(); + private X509PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor(); @Override protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractorTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractorTests.java new file mode 100644 index 0000000000..ebc1064fdc --- /dev/null +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractorTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.authentication.preauth.x509; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +/** + * Tests for {@link SubjectX500PrincipalExtractor}. + * + * @author Max Batischev + */ +public class SubjectX500PrincipalExtractorTests { + + private final SubjectX500PrincipalExtractor extractor = new SubjectX500PrincipalExtractor(); + + @Test + void extractWhenCnPatternSetThenExtractsPrincipalName() throws Exception { + Object principal = this.extractor.extractPrincipal(X509TestUtils.buildTestCertificate()); + + assertThat(principal).isEqualTo("Luke Taylor"); + } + + @Test + void extractWhenEmailPatternSetThenExtractsPrincipalName() throws Exception { + this.extractor.setExtractPrincipalNameFromEmail(true); + + Object principal = this.extractor.extractPrincipal(X509TestUtils.buildTestCertificate()); + + assertThat(principal).isEqualTo("luke@monkeymachine"); + } + + @Test + void extractWhenCnAtEndThenExtractsPrincipalName() throws Exception { + Object principal = this.extractor.extractPrincipal(X509TestUtils.buildTestCertificateWithCnAtEnd()); + + assertThat(principal).isEqualTo("Duke"); + } + + @Test + void setMessageSourceWhenNullThenThrowsException() { + assertThatIllegalArgumentException().isThrownBy(() -> this.extractor.setMessageSource(null)); + } + + @Test + void extractWhenCertificateIsNullThenFails() { + assertThatIllegalArgumentException().isThrownBy(() -> this.extractor.extractPrincipal(null)); + } + +} From 5f2efbea6a9432c11f2bb0793ea8edf75a907e8b Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:03:20 -0500 Subject: [PATCH 331/504] Remove unused statement --- .../preauth/x509/SubjectDnX509PrincipalExtractor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java index ffa217d8d5..8e77082e3c 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java @@ -16,7 +16,6 @@ package org.springframework.security.web.authentication.preauth.x509; -import java.security.Principal; import java.security.cert.X509Certificate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -62,7 +61,6 @@ public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor, @Override public Object extractPrincipal(X509Certificate clientCert) { // String subjectDN = clientCert.getSubjectX500Principal().getName(); - Principal principal = clientCert.getSubjectDN(); String subjectDN = clientCert.getSubjectDN().getName(); this.logger.debug(LogMessage.format("Subject DN is '%s'", subjectDN)); Matcher matcher = this.subjectDnPattern.matcher(subjectDN); From f690a7f3df302949963311229b6702619c3c7c64 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:41:56 -0500 Subject: [PATCH 332/504] Encapsulate extractPrincipalNameFromEmail property This simplifies the logic when extracting the principal and allows more flexibility in the future by allowing the format and regex to be added as setters. --- .../x509/SubjectX500PrincipalExtractor.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java index 4b735c0528..bb8aa26589 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java @@ -39,29 +39,31 @@ import org.springframework.util.Assert; * format RFC1779 will be used: DN is extracted from EMAIlADDRESS. * * @author Max Batischev + * @author Rob Winch * @since 7.0 */ public final class SubjectX500PrincipalExtractor implements X509PrincipalExtractor, MessageSourceAware { private final Log logger = LogFactory.getLog(getClass()); + private static final Pattern EMAIL_SUBJECT_DN_PATTERN = Pattern.compile("OID.1.2.840.113549.1.9.1=(.*?)(?:,|$)", + Pattern.CASE_INSENSITIVE); + + private static final Pattern CN_SUBJECT_DN_PATTERN = Pattern.compile("CN=(.*?)(?:,|$)", Pattern.CASE_INSENSITIVE); + private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); - private boolean extractPrincipalNameFromEmail = false; + private Pattern subjectDnPattern = CN_SUBJECT_DN_PATTERN; - private final Pattern cnSubjectDnPattern = Pattern.compile("CN=(.*?)(?:,|$)", Pattern.CASE_INSENSITIVE); - - private final Pattern emailSubjectDnPattern = Pattern.compile("OID.1.2.840.113549.1.9.1=(.*?)(?:,|$)", - Pattern.CASE_INSENSITIVE); + private String x500PrincipalFormat = X500Principal.RFC2253; @Override public Object extractPrincipal(X509Certificate clientCert) { Assert.notNull(clientCert, "clientCert cannot be null"); X500Principal principal = clientCert.getSubjectX500Principal(); - String subjectDN = this.extractPrincipalNameFromEmail ? principal.getName("RFC1779") : principal.getName(); + String subjectDN = principal.getName(this.x500PrincipalFormat); this.logger.debug(LogMessage.format("Subject DN is '%s'", subjectDN)); - Matcher matcher = this.extractPrincipalNameFromEmail ? this.emailSubjectDnPattern.matcher(subjectDN) - : this.cnSubjectDnPattern.matcher(subjectDN); + Matcher matcher = this.subjectDnPattern.matcher(subjectDN); if (!matcher.find()) { throw new BadCredentialsException(this.messages.getMessage("SubjectX500PrincipalExtractor.noMatching", new Object[] { subjectDN }, "No matching pattern was found in subject DN: {0}")); @@ -82,7 +84,14 @@ public final class SubjectX500PrincipalExtractor implements X509PrincipalExtract * @param extractPrincipalNameFromEmail whether to extract DN from EMAIlADDRESS */ public void setExtractPrincipalNameFromEmail(boolean extractPrincipalNameFromEmail) { - this.extractPrincipalNameFromEmail = extractPrincipalNameFromEmail; + if (extractPrincipalNameFromEmail) { + this.subjectDnPattern = EMAIL_SUBJECT_DN_PATTERN; + this.x500PrincipalFormat = X500Principal.RFC1779; + } + else { + this.subjectDnPattern = CN_SUBJECT_DN_PATTERN; + this.x500PrincipalFormat = X500Principal.RFC2253; + } } } From 2b740b7f1fe8130be0c6b3c7624b01d91ae47bf5 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:13:10 -0500 Subject: [PATCH 333/504] Update SubjectX500PrincipalExtractor Javadoc - Provide more details on how the principalName is extracted - Update to specify an OID is used for emailAddress --- .../x509/SubjectX500PrincipalExtractor.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java index bb8aa26589..9472be2cc7 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java @@ -34,9 +34,10 @@ import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.util.Assert; /** - * Obtains the principal from a certificate using RFC2253 and RFC1779 formats. By default, - * RFC2253 is used: DN is extracted from CN. If extractPrincipalNameFromEmail is true then - * format RFC1779 will be used: DN is extracted from EMAIlADDRESS. + * Extracts the principal from the {@link X500Principal#getName(String)} returned by + * {@link X509Certificate#getSubjectX500Principal()} passed into + * {@link #extractPrincipal(X509Certificate)} depending on the value of + * {@link #setExtractPrincipalNameFromEmail(boolean)}. * * @author Max Batischev * @author Rob Winch @@ -80,8 +81,26 @@ public final class SubjectX500PrincipalExtractor implements X509PrincipalExtract } /** - * If true then DN will be extracted from EMAIlADDRESS, defaults to {@code false} - * @param extractPrincipalNameFromEmail whether to extract DN from EMAIlADDRESS + * Sets if the principal name should be extracted from the emailAddress or CN + * attribute (default). + * + * By default, the format {@link X500Principal#RFC2253} is passed to + * {@link X500Principal#getName(String)} and the principal is extracted from the CN + * attribute as defined in + * Converting + * AttributeTypeAndValue of RFC2253. + * + * If {@link #setExtractPrincipalNameFromEmail(boolean)} is {@code true}, then the + * format {@link X500Principal#RFC2253} is passed to + * {@link X500Principal#getName(String)} and the principal is extracted from the + * OID.1.2.840.113549.1.9.1 + * (emailAddress) attribute as defined in + * Section 2.3 of + * RFC1779. + * @param extractPrincipalNameFromEmail whether to extract the principal from the + * emailAddress (default false) + * @see RFC2253 + * @see RFC1779 */ public void setExtractPrincipalNameFromEmail(boolean extractPrincipalNameFromEmail) { if (extractPrincipalNameFromEmail) { From 88ed4a5ccfa312fcf8244c82ffbe727935738d84 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 10 Jun 2025 15:22:20 -0500 Subject: [PATCH 334/504] Use principalExtractor reference instead of properties --- .../web/configurers/X509Configurer.java | 27 +--- .../http/AuthenticationConfigBuilder.java | 16 +-- .../security/config/annotation/web/X509Dsl.kt | 1 + .../security/config/spring-security-7.0.rnc | 3 - .../security/config/spring-security-7.0.xsd | 6 - .../web/configurers/X509ConfigurerTests.java | 119 ++++++++++++------ config/src/test/resources/max.cer | 17 --- .../servlet/appendix/namespace/http.adoc | 3 - 8 files changed, 85 insertions(+), 107 deletions(-) delete mode 100644 config/src/test/resources/max.cer diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java index b9b766a14d..d6241a0fbe 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java @@ -33,7 +33,6 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails; import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; -import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; @@ -75,7 +74,6 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR * * @author Rob Winch * @author Ngoc Nhan - * @author Max Batischev * @since 3.2 */ public final class X509Configurer> @@ -163,38 +161,17 @@ public final class X509Configurer> * @param subjectPrincipalRegex the regex to extract the user principal from the * certificate (i.e. "CN=(.*?)(?:,|$)"). * @return the {@link X509Configurer} for further customizations - * @deprecated Please use {{@link #extractPrincipalNameFromEmail(boolean)}} instead + * @deprecated Please use {{@link #x509PrincipalExtractor(X509PrincipalExtractor)} + * instead */ @Deprecated public X509Configurer subjectPrincipalRegex(String subjectPrincipalRegex) { - if (this.x509PrincipalExtractor instanceof SubjectX500PrincipalExtractor) { - throw new IllegalStateException( - "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " - + "Please use one or the other."); - } SubjectDnX509PrincipalExtractor principalExtractor = new SubjectDnX509PrincipalExtractor(); principalExtractor.setSubjectDnRegex(subjectPrincipalRegex); this.x509PrincipalExtractor = principalExtractor; return this; } - /** - * If true then DN will be extracted from EMAIlADDRESS, defaults to {@code false} - * @param extractPrincipalNameFromEmail whether to extract DN from EMAIlADDRESS - * @since 7.0 - */ - public X509Configurer extractPrincipalNameFromEmail(boolean extractPrincipalNameFromEmail) { - if (this.x509PrincipalExtractor instanceof SubjectDnX509PrincipalExtractor) { - throw new IllegalStateException( - "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " - + "Please use one or the other."); - } - SubjectX500PrincipalExtractor extractor = new SubjectX500PrincipalExtractor(); - extractor.setExtractPrincipalNameFromEmail(extractPrincipalNameFromEmail); - this.x509PrincipalExtractor = extractor; - return this; - } - @Override public void init(H http) { PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider(); diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java index 9b6ee210ac..f997e5fa5e 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +57,6 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedG import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource; import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; -import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter; @@ -523,25 +522,12 @@ final class AuthenticationConfigBuilder { filterBuilder.addPropertyValue("securityContextHolderStrategy", authenticationFilterSecurityContextHolderStrategyRef); String regex = x509Elt.getAttribute("subject-principal-regex"); - String extractPrincipalNameFromEmail = x509Elt.getAttribute("extract-principal-name-from-email"); - if (StringUtils.hasText(regex) && StringUtils.hasText(extractPrincipalNameFromEmail)) { - throw new IllegalStateException( - "Cannot use subjectPrincipalRegex and extractPrincipalNameFromEmail together. " - + "Please use one or the other."); - } if (StringUtils.hasText(regex)) { BeanDefinitionBuilder extractor = BeanDefinitionBuilder .rootBeanDefinition(SubjectDnX509PrincipalExtractor.class); extractor.addPropertyValue("subjectDnRegex", regex); filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); } - if (StringUtils.hasText(extractPrincipalNameFromEmail)) { - BeanDefinitionBuilder extractor = BeanDefinitionBuilder - .rootBeanDefinition(SubjectX500PrincipalExtractor.class); - extractor.addPropertyValue("extractPrincipalNameFromEmail", - Boolean.parseBoolean(extractPrincipalNameFromEmail)); - filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); - } injectAuthenticationDetailsSource(x509Elt, filterBuilder); filter = (RootBeanDefinition) filterBuilder.getBeanDefinition(); createPrauthEntryPoint(x509Elt); diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/X509Dsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/X509Dsl.kt index f36897604a..514ace50b3 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/X509Dsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/X509Dsl.kt @@ -51,6 +51,7 @@ class X509Dsl { var authenticationDetailsSource: AuthenticationDetailsSource? = null var userDetailsService: UserDetailsService? = null var authenticationUserDetailsService: AuthenticationUserDetailsService? = null + @Deprecated("Use x509PrincipalExtractor instead") var subjectPrincipalRegex: String? = null diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc index 1236a2aec5..bbf8622dfe 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -1053,9 +1053,6 @@ x509.attlist &= x509.attlist &= ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter attribute authentication-details-source-ref {xsd:token}? -x509.attlist &= - ## If true then DN will be extracted from EMAIlADDRESS - attribute extract-principal-name-from-email {xsd:token}? jee = ## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index ed82f3468b..2e3d6cf275 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -2917,12 +2917,6 @@ - - - If true then DN will be extracted from EMAIlADDRESS - - - diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java index 38983691e1..63a3a963df 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,9 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils; import org.springframework.test.web.servlet.MockMvc; import static org.assertj.core.api.Assertions.assertThat; @@ -123,16 +125,6 @@ public class X509ConfigurerTests { // @formatter:on } - @Test - public void x509WhenExtractPrincipalNameFromEmailIsTrueThenUsesEmailAddressToExtractPrincipal() throws Exception { - this.spring.register(EmailPrincipalConfig.class).autowire(); - X509Certificate certificate = loadCert("max.cer"); - // @formatter:off - this.mvc.perform(get("/").with(x509(certificate))) - .andExpect(authenticated().withUsername("maxbatischev@gmail.com")); - // @formatter:on - } - @Test public void x509WhenUserDetailsServiceNotConfiguredThenUsesBean() throws Exception { this.spring.register(UserDetailsServiceBeanConfig.class).autowire(); @@ -165,6 +157,28 @@ public class X509ConfigurerTests { // @formatter:on } + @Test + public void x509WhenSubjectX500PrincipalExtractor() throws Exception { + this.spring.register(SubjectX500PrincipalExtractorConfig.class).autowire(); + X509Certificate certificate = loadCert("rod.cer"); + // @formatter:off + this.mvc.perform(get("/").with(x509(certificate))) + .andExpect((result) -> assertThat(result.getRequest().getSession(false)).isNull()) + .andExpect(authenticated().withUsername("rod")); + // @formatter:on + } + + @Test + public void x509WhenSubjectX500PrincipalExtractorBean() throws Exception { + this.spring.register(SubjectX500PrincipalExtractorEmailConfig.class).autowire(); + X509Certificate certificate = X509TestUtils.buildTestCertificate(); + // @formatter:off + this.mvc.perform(get("/").with(x509(certificate))) + .andExpect((result) -> assertThat(result.getRequest().getSession(false)).isNull()) + .andExpect(authenticated().withUsername("luke@monkeymachine")); + // @formatter:on + } + private T loadCert(String location) { try (InputStream is = new ClassPathResource(location).getInputStream()) { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); @@ -287,33 +301,6 @@ public class X509ConfigurerTests { } - @Configuration - @EnableWebSecurity - static class EmailPrincipalConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .x509((x509) -> - x509.extractPrincipalNameFromEmail(true) - ); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("maxbatischev@gmail.com") - .password("password") - .roles("USER", "ADMIN") - .build(); - return new InMemoryUserDetailsManager(user); - } - - } - @Configuration @EnableWebSecurity static class UserDetailsServiceBeanConfig { @@ -397,4 +384,60 @@ public class X509ConfigurerTests { } + @Configuration + @EnableWebSecurity + static class SubjectX500PrincipalExtractorConfig { + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .x509((x509) -> x509 + .x509PrincipalExtractor(new SubjectX500PrincipalExtractor()) + ); + // @formatter:on + return http.build(); + } + + @Bean + UserDetailsService userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("rod") + .password("password") + .roles("USER", "ADMIN") + .build(); + return new InMemoryUserDetailsManager(user); + } + + } + + @Configuration + @EnableWebSecurity + static class SubjectX500PrincipalExtractorEmailConfig { + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor(); + principalExtractor.setExtractPrincipalNameFromEmail(true); + // @formatter:off + http + .x509((x509) -> x509 + .x509PrincipalExtractor(principalExtractor) + ); + // @formatter:on + return http.build(); + } + + @Bean + UserDetailsService userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("luke@monkeymachine") + .password("password") + .roles("USER", "ADMIN") + .build(); + return new InMemoryUserDetailsManager(user); + } + + } + } diff --git a/config/src/test/resources/max.cer b/config/src/test/resources/max.cer deleted file mode 100644 index bd79b1f096..0000000000 --- a/config/src/test/resources/max.cer +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICojCCAgugAwIBAgIBADANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJydTEP -MA0GA1UECAwGTW9zY293MQ8wDQYDVQQKDAZTcHJpbmcxFjAUBgNVBAMMDU1heCBC -YXRpc2NoZXYxJTAjBgkqhkiG9w0BCQEWFm1heGJhdGlzY2hldkBnbWFpbC5jb20w -HhcNMjUwNTE0MTcyODM5WhcNMjYwNTE0MTcyODM5WjBuMQswCQYDVQQGEwJydTEP -MA0GA1UECAwGTW9zY293MQ8wDQYDVQQKDAZTcHJpbmcxFjAUBgNVBAMMDU1heCBC -YXRpc2NoZXYxJTAjBgkqhkiG9w0BCQEWFm1heGJhdGlzY2hldkBnbWFpbC5jb20w -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVZ2K/iOINeHZ4XAV3QmNRgS+iB -Vw0fW07uzYkCoSZU1lOBQE0k8+fdM2+X9AsgwfRCE3tUZquPApEKynB5V9Seh+bR -vc9aj7PunMyN+zjRU6X7/BL3VqLfrJLSc15bQaSN1phJ6NT+BTXPTuiPbXldnJLC -wVo6PView83yZ335AgMBAAGjUDBOMB0GA1UdDgQWBBQhyQfxL2ZYotcS8AmMJtli -2IRAMTAfBgNVHSMEGDAWgBQhyQfxL2ZYotcS8AmMJtli2IRAMTAMBgNVHRMEBTAD -AQH/MA0GCSqGSIb3DQEBDQUAA4GBAIIIJxpsTPtUEnePAqqgVFWDKC2CExhtCBYL -MjLSC+7E9OlfuuX1joAsD4Yv86k4Ox836D0KQtINtg3y6D8O+HSylhVg1xtOiK7l -ElXVRepB8GcX3vf9F58v9s++cSDvXf8vJu/O7nI4fv9C5SfUtMY4JPh/3MTsyl8O -tgxTKjvO ------END CERTIFICATE----- diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 812706ae1d..8979d5ad29 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -2229,9 +2229,6 @@ Defines a regular expression which will be used to extract the username from the Allows a specific `UserDetailsService` to be used with X.509 in the case where multiple instances are configured. If not set, an attempt will be made to locate a suitable instance automatically and use that. -[[nsa-x509-extract-principal-name-from-email]] -* **extract-principal-name-from-email** -If true then DN will be extracted from EMAIlADDRESS. [[nsa-filter-chain-map]] == From 7bf2730a5359b2a28b6de825cd7ca138ba85cfa0 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:05:43 -0500 Subject: [PATCH 335/504] Add x509@principal-extractor-ref Enables customizing the X500PrincipalExtractor --- .../http/AuthenticationConfigBuilder.java | 18 ++++++-- .../security/config/spring-security-7.0.rnc | 3 ++ .../security/config/spring-security-7.0.xsd | 6 +++ .../config/http/MiscHttpConfigTests.java | 23 +++++++++++ ...pConfigTests-X509PrincipalExtractorRef.xml | 41 +++++++++++++++++++ ...alExtractorRefAndSubjectPrincipalRegex.xml | 41 +++++++++++++++++++ .../servlet/appendix/namespace/http.adoc | 4 ++ 7 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRef.xml create mode 100644 config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRefAndSubjectPrincipalRegex.xml diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java index f997e5fa5e..55efc57a17 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java @@ -521,11 +521,23 @@ final class AuthenticationConfigBuilder { filterBuilder.addPropertyValue("authenticationManager", authManager); filterBuilder.addPropertyValue("securityContextHolderStrategy", authenticationFilterSecurityContextHolderStrategyRef); - String regex = x509Elt.getAttribute("subject-principal-regex"); - if (StringUtils.hasText(regex)) { + String principalExtractorRef = x509Elt.getAttribute("principal-extractor-ref"); + String subjectPrincipalRegex = x509Elt.getAttribute("subject-principal-regex"); + boolean hasPrincipalExtractorRef = StringUtils.hasText(principalExtractorRef); + boolean hasSubjectPrincipalRegex = StringUtils.hasText(subjectPrincipalRegex); + if (hasPrincipalExtractorRef && hasSubjectPrincipalRegex) { + this.pc.getReaderContext() + .error("The attribute 'principal-extractor-ref' cannot be used together with the 'subject-principal-regex' attribute within <" + + Elements.X509 + ">", this.pc.extractSource(x509Elt)); + } + if (hasPrincipalExtractorRef) { + RuntimeBeanReference principalExtractor = new RuntimeBeanReference(principalExtractorRef); + filterBuilder.addPropertyValue("principalExtractor", principalExtractor); + } + if (hasSubjectPrincipalRegex) { BeanDefinitionBuilder extractor = BeanDefinitionBuilder .rootBeanDefinition(SubjectDnX509PrincipalExtractor.class); - extractor.addPropertyValue("subjectDnRegex", regex); + extractor.addPropertyValue("subjectDnRegex", subjectPrincipalRegex); filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition()); } injectAuthenticationDetailsSource(x509Elt, filterBuilder); diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc index bbf8622dfe..d9a8d4f9d5 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.rnc @@ -1053,6 +1053,9 @@ x509.attlist &= x509.attlist &= ## Reference to an AuthenticationDetailsSource which will be used by the authentication filter attribute authentication-details-source-ref {xsd:token}? +x509.attlist &= + ## Reference to an X509PrincipalExtractor which will be used by the authentication filter + attribute principal-extractor-ref {xsd:token}? jee = ## Adds a J2eePreAuthenticatedProcessingFilter to the filter chain to provide integration with container authentication. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 2e3d6cf275..4ff414800b 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -2917,6 +2917,12 @@ + + + Reference to an X509PrincipalExtractor which will be used by the authentication filter + + + diff --git a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java index 5221350cde..10927906ea 100644 --- a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.OutputStream; import java.security.AccessController; import java.security.Principal; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -91,6 +92,7 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultResourcesFilter; @@ -398,6 +400,27 @@ public class MiscHttpConfigTests { .containsSubsequence(CsrfFilter.class, X509AuthenticationFilter.class, ExceptionTranslationFilter.class); } + @Test + public void getWhenUsingX509PrincipalExtractorRef() throws Exception { + this.spring.configLocations(xml("X509PrincipalExtractorRef")).autowire(); + X509Certificate certificate = X509TestUtils.buildTestCertificate(); + RequestPostProcessor x509 = x509(certificate); + // @formatter:off + this.mvc.perform(get("/protected").with(x509)) + .andExpect(status().isOk()); + // @formatter:on + } + + @Test + public void getWhenUsingX509PrincipalExtractorRefAndSubjectPrincipalRegex() throws Exception { + String xmlResourceName = "X509PrincipalExtractorRefAndSubjectPrincipalRegex"; + // @formatter:off + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> this.spring.configLocations(xml(xmlResourceName)).autowire()) + .withMessage("Configuration problem: The attribute 'principal-extractor-ref' cannot be used together with the 'subject-principal-regex' attribute within \n" + "Offending resource: class path resource [org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRefAndSubjectPrincipalRegex.xml]"); + // @formatter:on + } + @Test public void getWhenUsingX509AndPropertyPlaceholderThenSubjectPrincipalRegexIsConfigured() throws Exception { System.setProperty("subject_principal_regex", "OU=(.*?)(?:,|$)"); diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRef.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRef.xml new file mode 100644 index 0000000000..51a3a1bbf1 --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRef.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRefAndSubjectPrincipalRegex.xml b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRefAndSubjectPrincipalRegex.xml new file mode 100644 index 0000000000..1fc7e0f12c --- /dev/null +++ b/config/src/test/resources/org/springframework/security/config/http/MiscHttpConfigTests-X509PrincipalExtractorRefAndSubjectPrincipalRegex.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 8979d5ad29..555a1b4323 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -2218,6 +2218,10 @@ A `PreAuthenticatedAuthenticationProvider` will also be created which delegates * **authentication-details-source-ref** A reference to an `AuthenticationDetailsSource` +[[nsa-x509-principal-extractor-ref]] +* **principal-extractor-ref** +Reference to an `X509PrincipalExtractor` which will be used by the authentication filter. + [[nsa-x509-subject-principal-regex]] * **subject-principal-regex** From e3add59550f516111f755c7f4591bb501c05fdd5 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Wed, 11 Jun 2025 08:41:38 -0500 Subject: [PATCH 336/504] Update x509 Reference - Use include-code - Demo how to customize SubjectX500PrincipalExtractor --- docs/antora.yml | 1 + .../pages/reactive/authentication/x509.adoc | 94 +---------- .../pages/servlet/authentication/x509.adoc | 42 ++--- .../reactivex509/CustomX509Configuration.java | 74 +++++++++ .../DefaultX509Configuration.java | 67 ++++++++ .../reactivex509/X509ConfigurationTests.java | 148 ++++++++++++++++++ .../CustomX509Configuration.java | 75 +++++++++ .../DefaultX509Configuration.java | 67 ++++++++ .../X509ConfigurationTests.java | 103 ++++++++++++ .../reactivex509/CustomX509Configuration.kt | 74 +++++++++ .../reactivex509/DefaultX509Configuration.kt | 64 ++++++++ .../reactivex509/X509ConfigurationTests.kt | 131 ++++++++++++++++ .../CustomX509Configuration.kt | 69 ++++++++ .../DefaultX509Configuration.kt | 64 ++++++++ .../X509ConfigurationTests.kt | 75 +++++++++ .../CustomX509Configuration.xml | 45 ++++++ .../DefaultX509Configuration.xml | 39 +++++ 17 files changed, 1118 insertions(+), 114 deletions(-) create mode 100644 docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java create mode 100644 docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java create mode 100644 docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/X509ConfigurationTests.java create mode 100644 docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.java create mode 100644 docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java create mode 100644 docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/X509ConfigurationTests.java create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/CustomX509Configuration.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/DefaultX509Configuration.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/CustomX509Configuration.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/DefaultX509Configuration.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/X509ConfigurationTests.kt create mode 100644 docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.xml create mode 100644 docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.xml diff --git a/docs/antora.yml b/docs/antora.yml index 02262db72e..c6a145aaab 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -18,3 +18,4 @@ asciidoc: gh-url: "https://github.com/spring-projects/spring-security/tree/{gh-tag}" include-java: 'example$docs-src/test/java/org/springframework/security/docs' include-kotlin: 'example$docs-src/test/kotlin/org/springframework/security/kt/docs' + include-xml: 'example$docs-src/test/resources/org/springframework/security/docs' diff --git a/docs/modules/ROOT/pages/reactive/authentication/x509.adoc b/docs/modules/ROOT/pages/reactive/authentication/x509.adoc index a077dd5c65..947084423c 100644 --- a/docs/modules/ROOT/pages/reactive/authentication/x509.adoc +++ b/docs/modules/ROOT/pages/reactive/authentication/x509.adoc @@ -5,98 +5,16 @@ Similar to xref:servlet/authentication/x509.adoc#servlet-x509[Servlet X.509 auth The following example shows a reactive x509 security configuration: -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - http - .x509(withDefaults()) - .authorizeExchange(exchanges -> exchanges - .anyExchange().permitAll() - ); - return http.build(); -} ----- +include-code::./DefaultX509Configuration[tag=springSecurity,indent=0] -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http { - x509 { } - authorizeExchange { - authorize(anyExchange, authenticated) - } - } -} ----- -====== - -In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. The default principal extractor is `SubjectDnX509PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. +In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. +The default principal extractor is `SubjectX500PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. +The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. The following example demonstrates how these defaults can be overridden: -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { - SubjectDnX509PrincipalExtractor principalExtractor = - new SubjectDnX509PrincipalExtractor(); +include-code::./CustomX509Configuration[tag=springSecurity,indent=0] - principalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)"); - - ReactiveAuthenticationManager authenticationManager = authentication -> { - authentication.setAuthenticated("Trusted Org Unit".equals(authentication.getName())); - return Mono.just(authentication); - }; - - http - .x509(x509 -> x509 - .principalExtractor(principalExtractor) - .authenticationManager(authenticationManager) - ) - .authorizeExchange(exchanges -> exchanges - .anyExchange().authenticated() - ); - return http.build(); -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? { - val customPrincipalExtractor = SubjectDnX509PrincipalExtractor() - customPrincipalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)") - val customAuthenticationManager = ReactiveAuthenticationManager { authentication: Authentication -> - authentication.isAuthenticated = "Trusted Org Unit" == authentication.name - Mono.just(authentication) - } - return http { - x509 { - principalExtractor = customPrincipalExtractor - authenticationManager = customAuthenticationManager - } - authorizeExchange { - authorize(anyExchange, authenticated) - } - } -} ----- -====== - -In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using `ReactiveUserDetailsService` is not performed at all. Instead, if the provided certificate issued to an OU named "`Trusted Org Unit`", a request is authenticated. +In the previous example, a username is extracted from the `emailAddress` field of a client certificate instead of CN, and account lookup uses a custom `ReactiveAuthenticationManager` instance. For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, see https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. diff --git a/docs/modules/ROOT/pages/servlet/authentication/x509.adoc b/docs/modules/ROOT/pages/servlet/authentication/x509.adoc index 26dbb1a900..2d670a632e 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/x509.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/x509.adoc @@ -14,37 +14,27 @@ You should get this working before trying it out with Spring Security. The Spring Security X.509 module extracts the certificate by using a filter. It maps the certificate to an application user and loads that user's set of granted authorities for use with the standard Spring Security infrastructure. - +[[servlet-x509-config]] == Adding X.509 Authentication to Your Web Application -Enabling X.509 client authentication is very straightforward. -To do so, add the `` element to your http security namespace configuration: -[source,xml] ----- - -... - ; - ----- +Similar to xref:reactive/authentication/x509.adoc[Reactive X.509 authentication], the servlet x509 authentication filter allows extracting an authentication token from a certificate provided by a client. -The element has two optional attributes: +The following example shows a reactive x509 security configuration: -* `subject-principal-regex`. -The regular expression used to extract a username from the certificate's subject name. -The default value is shown in the preceding listing. -This is the username that is passed to the `UserDetailsService` to load the authorities for the user. -* `user-service-ref`. -This is the bean ID of the `UserDetailsService` to be used with X.509. -It is not needed if there is only one defined in your application context. +include-code::./DefaultX509Configuration[tag=springSecurity,indent=0] + +In the preceding configuration, when neither `principalExtractor` nor `authenticationManager` is provided, defaults are used. +The default principal extractor is `SubjectX500PrincipalExtractor`, which extracts the CN (common name) field from a certificate provided by a client. +The default authentication manager is `ReactivePreAuthenticatedAuthenticationManager`, which performs user account validation, checking that a user account with a name extracted by `principalExtractor` exists and that it is not locked, disabled, or expired. + +The following example demonstrates how these defaults can be overridden: + +include-code::./CustomX509Configuration[tag=springSecurity,indent=0] + +In the previous example, a username is extracted from the `emailAddress` field of a client certificate instead of CN, and account lookup uses a custom `ReactiveAuthenticationManager` instance. + +For an example of configuring Netty and `WebClient` or `curl` command-line tool to use mutual TLS and enable X.509 authentication, see https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509. -The `subject-principal-regex` should contain a single group. -For example, the default expression (`CN=(.*?)`) matches the common name field. -So, if the subject name in the certificate is "CN=Jimi Hendrix, OU=...", this gives a user name of "Jimi Hendrix". -The matches are case insensitive. -So "emailAddress=(+.*?+)," matches "EMAILADDRESS=jimi@hendrix.org,CN=...", giving a user name "jimi@hendrix.org". -If the client presents a certificate and a valid username is successfully extracted, there should be a valid `Authentication` object in the security context. -If no certificate is found or no corresponding user could be found, the security context remains empty. -This means that you can use X.509 authentication with other options, such as a form-based login. [[x509-ssl-config]] == Setting up SSL in Tomcat diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java new file mode 100644 index 0000000000..8f7f8c8278 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.reactivex509; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.authentication.ReactivePreAuthenticatedAuthenticationManager; +import org.springframework.web.reactive.config.EnableWebFlux; + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@EnableWebFluxSecurity +@EnableWebFlux +public class CustomX509Configuration { + + // tag::springSecurity[] + @Bean + SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { + SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor(); + principalExtractor.setExtractPrincipalNameFromEmail(true); + + // @formatter:off + UserDetails user = User + .withUsername("luke@monkeymachine") + .password("password") + .roles("USER") + .build(); + // @formatter:on + + ReactiveUserDetailsService users = new MapReactiveUserDetailsService(user); + ReactiveAuthenticationManager authenticationManager = new ReactivePreAuthenticatedAuthenticationManager(users); + + // @formatter:off + http + .x509(x509 -> x509 + .principalExtractor(principalExtractor) + .authenticationManager(authenticationManager) + ) + .authorizeExchange(exchanges -> exchanges + .anyExchange().authenticated() + ); + // @formatter:on + return http.build(); + } + // end::springSecurity[] + +} diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java new file mode 100644 index 0000000000..0fd17fa1d8 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.reactivex509; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.web.reactive.config.EnableWebFlux; + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@EnableWebFluxSecurity +@EnableWebFlux +public class DefaultX509Configuration { + + // tag::springSecurity[] + @Bean + SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { + // @formatter:off + http + .x509(Customizer.withDefaults()) + .authorizeExchange(exchanges -> exchanges + .anyExchange().authenticated() + ); + // @formatter:on + return http.build(); + } + // end::springSecurity[] + + @Bean + ReactiveUserDetailsService userDetailsService() { + // @formatter:off + UserDetails user = User + .withUsername("rod") + .password("password") + .roles("USER") + .build(); + // @formatter:on + + return new MapReactiveUserDetailsService(user); + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/X509ConfigurationTests.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/X509ConfigurationTests.java new file mode 100644 index 0000000000..475787da4f --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/X509ConfigurationTests.java @@ -0,0 +1,148 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.reactive.authentication.reactivex509; + +import java.io.InputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.SslInfo; +import org.springframework.security.config.test.SpringTestContext; +import org.springframework.security.config.test.SpringTestContextExtension; +import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClientConfigurer; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + +/** + * Tests {@link CustomX509Configuration}. + * + * @author Rob Winch + */ +@ExtendWith(SpringTestContextExtension.class) +public class X509ConfigurationTests { + + public final SpringTestContext spring = new SpringTestContext(this); + + WebTestClient client; + + @Autowired + void setSpringSecurityFilterChain(WebFilter springSecurityFilterChain) { + this.client = WebTestClient.bindToController(WebTestClientBuilder.Http200RestController.class) + .webFilter(springSecurityFilterChain) + .apply(springSecurity()) + .configureClient() + .build(); + } + + @Test + void x509WhenDefaultX509Configuration() throws Exception { + this.spring.register(DefaultX509Configuration.class).autowire(); + X509Certificate certificate = loadCert("rod.cer"); + // @formatter:off + this.client + .mutateWith(x509(certificate)) + .get() + .uri("/") + .exchange() + .expectStatus().isOk(); + // @formatter:on + } + + @Test + void x509WhenCustomX509Configuration() throws Exception { + this.spring.register(CustomX509Configuration.class).autowire(); + X509Certificate certificate = X509TestUtils.buildTestCertificate(); + // @formatter:off + this.client + .mutateWith(x509(certificate)) + .get() + .uri("/") + .exchange() + .expectStatus().isOk(); + // @formatter:on + } + + private static @NotNull WebTestClientConfigurer x509(X509Certificate certificate) { + return (builder, httpHandlerBuilder, connector) -> { + builder.apply(new WebTestClientConfigurer() { + @Override + public void afterConfigurerAdded(WebTestClient.Builder builder, + @Nullable WebHttpHandlerBuilder httpHandlerBuilder, + @Nullable ClientHttpConnector connector) { + SslInfo sslInfo = new SslInfo() { + @Override + public @Nullable String getSessionId() { + return "sessionId"; + } + + @Override + public X509Certificate @Nullable [] getPeerCertificates() { + return new X509Certificate[] { certificate }; + } + }; + httpHandlerBuilder.filters((filters) -> filters.add(0, new SslInfoOverrideWebFilter(sslInfo))); + } + }); + }; + } + + private static class SslInfoOverrideWebFilter implements WebFilter { + private final SslInfo sslInfo; + + private SslInfoOverrideWebFilter(SslInfo sslInfo) { + this.sslInfo = sslInfo; + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + ServerHttpRequest sslInfoRequest = exchange.getRequest().mutate().sslInfo(sslInfo) + .build(); + ServerWebExchange sslInfoExchange = exchange.mutate().request(sslInfoRequest).build(); + return chain.filter(sslInfoExchange); + } + } + + private T loadCert(String location) { + try (InputStream is = new ClassPathResource(location).getInputStream()) { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (T) certFactory.generateCertificate(is); + } + catch (Exception ex) { + throw new IllegalArgumentException(ex); + } + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.java new file mode 100644 index 0000000000..70b46b7c54 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.servletx509config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebMvc +@EnableWebSecurity +@Configuration(proxyBeanMethods = false) +public class CustomX509Configuration { + + // tag::springSecurity[] + @Bean + DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception { + SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor(); + principalExtractor.setExtractPrincipalNameFromEmail(true); + + + // @formatter:off + http + .x509((x509) -> x509 + .x509PrincipalExtractor(principalExtractor) + ) + .authorizeHttpRequests((exchanges) -> exchanges + .anyRequest().authenticated() + ); + // @formatter:on + return http.build(); + } + // end::springSecurity[] + + @Bean + UserDetailsService userDetailsService() { + // @formatter:off + UserDetails user = User + .withUsername("luke@monkeymachine") + .password("password") + .roles("USER") + .build(); + // @formatter:on + + return new InMemoryUserDetailsManager(user); + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java new file mode 100644 index 0000000000..a347235386 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.servletx509config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebMvc +@EnableWebSecurity +@Configuration(proxyBeanMethods = false) +public class DefaultX509Configuration { + + // tag::springSecurity[] + @Bean + DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception { + // @formatter:off + http + .x509(Customizer.withDefaults()) + .authorizeHttpRequests(exchanges -> exchanges + .anyRequest().authenticated() + ); + // @formatter:on + return http.build(); + } + // end::springSecurity[] + + @Bean + UserDetailsService userDetailsService() { + // @formatter:off + UserDetails user = User + .withUsername("rod") + .password("password") + .roles("USER") + .build(); + // @formatter:on + + return new InMemoryUserDetailsManager(user); + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/X509ConfigurationTests.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/X509ConfigurationTests.java new file mode 100644 index 0000000000..c6aa6f6d41 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/X509ConfigurationTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.servlet.authentication.servletx509config; + +import java.io.InputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.SslInfo; +import org.springframework.security.config.test.SpringTestContext; +import org.springframework.security.config.test.SpringTestContextExtension; +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClientConfigurer; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Tests {@link CustomX509Configuration}. + * + * @author Rob Winch + */ +@ExtendWith(SpringTestContextExtension.class) +public class X509ConfigurationTests { + + public final SpringTestContext spring = new SpringTestContext(this); + + @Autowired + MockMvc mockMvc; + + @Test + void x509WhenDefaultX509Configuration() throws Exception { + this.spring.register(DefaultX509Configuration.class, Http200Controller.class).autowire(); + // @formatter:off + this.mockMvc.perform(get("/").with(x509("rod.cer"))) + .andExpect(status().isOk()) + .andExpect(authenticated().withUsername("rod")); + // @formatter:on + } + + @Test + void x509WhenDefaultX509ConfigurationXml() throws Exception { + this.spring.testConfigLocations("DefaultX509Configuration.xml").autowire(); + // @formatter:off + this.mockMvc.perform(get("/").with(x509("rod.cer"))) + .andExpect(authenticated().withUsername("rod")); + // @formatter:on + } + + @Test + void x509WhenCustomX509Configuration() throws Exception { + this.spring.register(CustomX509Configuration.class, Http200Controller.class).autowire(); + X509Certificate certificate = X509TestUtils.buildTestCertificate(); + // @formatter:off + this.mockMvc.perform(get("/").with(x509(certificate))) + .andExpect(status().isOk()) + .andExpect(authenticated().withUsername("luke@monkeymachine")); + // @formatter:on + } + + @RestController + static class Http200Controller { + @GetMapping("/**") + String ok() { + return "ok"; + } + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/CustomX509Configuration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/CustomX509Configuration.kt new file mode 100644 index 0000000000..78c4fbe34b --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/CustomX509Configuration.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.reactivex509 + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.ReactiveAuthenticationManager +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity.http +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService +import org.springframework.security.core.userdetails.ReactiveUserDetailsService +import org.springframework.security.core.userdetails.User +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor +import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.security.web.server.authentication.ReactivePreAuthenticatedAuthenticationManager +import org.springframework.web.reactive.config.EnableWebFlux + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebFlux +@EnableWebFluxSecurity +@Configuration(proxyBeanMethods = false) +class CustomX509Configuration { + + // tag::springSecurity[] + @Bean + fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + val extractor = SubjectX500PrincipalExtractor() + extractor.setExtractPrincipalNameFromEmail(true) + + // @formatter:off + val user = User + .withUsername("luke@monkeymachine") + .password("password") + .roles("USER") + .build() + // @formatter:on + + val users: ReactiveUserDetailsService = MapReactiveUserDetailsService(user) + val authentication: ReactiveAuthenticationManager = ReactivePreAuthenticatedAuthenticationManager(users) + + return http { + x509 { + principalExtractor = extractor + authenticationManager = authentication + } + authorizeExchange { + authorize(anyExchange, authenticated) + } + } + } + // end::springSecurity[] + + +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/DefaultX509Configuration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/DefaultX509Configuration.kt new file mode 100644 index 0000000000..61e5d65db5 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/DefaultX509Configuration.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.reactive.authentication.reactivex509 + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.config.web.server.invoke +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService +import org.springframework.security.core.userdetails.User +import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.web.reactive.config.EnableWebFlux + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebFlux +@EnableWebFluxSecurity +@Configuration(proxyBeanMethods = false) +class DefaultX509Configuration { + + // tag::springSecurity[] + @Bean + fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + x509 { } + authorizeExchange { + authorize(anyExchange, authenticated) + } + } + } + // end::springSecurity[] + + @Bean + fun userDetailsService(): MapReactiveUserDetailsService { + // @formatter:off + val user = User + .withUsername("rod") + .password("password") + .roles("USER") + .build() + // @formatter:on + + return MapReactiveUserDetailsService(user) + } + +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt new file mode 100644 index 0000000000..4802660f06 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.kt.docs.reactive.authentication.reactivex509 + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.core.io.ClassPathResource +import org.springframework.http.client.reactive.ClientHttpConnector +import org.springframework.http.server.reactive.SslInfo +import org.springframework.security.config.test.SpringTestContext +import org.springframework.security.config.test.SpringTestContextExtension +import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers +import org.springframework.security.test.web.reactive.server.WebTestClientBuilder.Http200RestController +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils +import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.test.web.reactive.server.WebTestClientConfigurer +import org.springframework.web.server.ServerWebExchange +import org.springframework.web.server.WebFilter +import org.springframework.web.server.WebFilterChain +import org.springframework.web.server.adapter.WebHttpHandlerBuilder +import reactor.core.publisher.Mono +import java.security.cert.Certificate +import java.security.cert.CertificateFactory +import java.security.cert.X509Certificate +import java.util.function.Consumer + +/** + * Tests [CustomX509Configuration]. + * + * @author Rob Winch + */ +@ExtendWith(SpringTestContextExtension::class) +class X509ConfigurationTests { + @JvmField + val spring: SpringTestContext = SpringTestContext(this) + + var client: WebTestClient? = null + + @Autowired + fun setSpringSecurityFilterChain(springSecurityFilterChain: WebFilter) { + this.client = WebTestClient + .bindToController(Http200RestController::class.java) + .webFilter(springSecurityFilterChain) + .apply(SecurityMockServerConfigurers.springSecurity()) + .configureClient() + .build() + } + + @Test + fun x509WhenDefaultX509Configuration() { + this.spring.register(DefaultX509Configuration::class.java).autowire() + val certificate = loadCert("rod.cer") + // @formatter:off + this.client!!.mutateWith(x509(certificate)) + .get() + .uri("/") + .exchange() + .expectStatus().isOk() + // @formatter:on + } + + @Test + fun x509WhenCustomX509Configuration() { + this.spring.register(CustomX509Configuration::class.java).autowire() + val certificate = X509TestUtils.buildTestCertificate() + // @formatter:off + this.client!!.mutateWith(x509(certificate)) + .get() + .uri("/") + .exchange() + .expectStatus().isOk() + // @formatter:on + } + + private class SslInfoOverrideWebFilter(private val sslInfo: SslInfo) : WebFilter { + override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono { + val sslInfoRequest = exchange.getRequest().mutate().sslInfo(sslInfo) + .build() + val sslInfoExchange = exchange.mutate().request(sslInfoRequest).build() + return chain.filter(sslInfoExchange) + } + } + + private fun loadCert(location: String): T { + try { + ClassPathResource(location).getInputStream().use { `is` -> + val certFactory = CertificateFactory.getInstance("X.509") + return certFactory.generateCertificate(`is`) as T + } + } catch (ex: Exception) { + throw IllegalArgumentException(ex) + } + } + + companion object { + private fun x509(certificate: X509Certificate): WebTestClientConfigurer { + return WebTestClientConfigurer { builder: WebTestClient.Builder, httpHandlerBuilder: WebHttpHandlerBuilder, connector: ClientHttpConnector? -> + + val sslInfo: SslInfo = object : SslInfo { + override fun getSessionId(): String { + return "sessionId" + } + + override fun getPeerCertificates(): Array { + return arrayOf(certificate) + } + } + httpHandlerBuilder.filters(Consumer { filters: MutableList -> + filters.add( + 0, + SslInfoOverrideWebFilter(sslInfo) + ) + }) + } + } + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/CustomX509Configuration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/CustomX509Configuration.kt new file mode 100644 index 0000000000..b079ce26fb --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/CustomX509Configuration.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.kt.docs.servlet.authentication.servlet509config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.security.web.DefaultSecurityFilterChain +import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor +import org.springframework.web.servlet.config.annotation.EnableWebMvc + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebMvc +@EnableWebSecurity +@Configuration(proxyBeanMethods = false) +class CustomX509Configuration { + // tag::springSecurity[] + @Bean + fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? { + val principalExtractor = SubjectX500PrincipalExtractor() + principalExtractor.setExtractPrincipalNameFromEmail(true) + + // @formatter:off + http { + authorizeHttpRequests { + authorize(anyRequest, authenticated) + } + x509 { + x509PrincipalExtractor = principalExtractor + } + } + return http.build() + } + // end::springSecurity[] + + @Bean + fun userDetailsService(): UserDetailsService { + // @formatter:off + val user = User + .withUsername("luke@monkeymachine") + .password("password") + .roles("USER") + .build() + // @formatter:on + return InMemoryUserDetailsManager(user) + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/DefaultX509Configuration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/DefaultX509Configuration.kt new file mode 100644 index 0000000000..3c777ebe32 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/DefaultX509Configuration.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.kt.docs.servlet.authentication.servlet509config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.invoke +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.security.web.DefaultSecurityFilterChain +import org.springframework.web.servlet.config.annotation.EnableWebMvc + +/** + * Demonstrates custom configuration for x509 reactive configuration. + * + * @author Rob Winch + */ +@EnableWebMvc +@EnableWebSecurity +@Configuration(proxyBeanMethods = false) +class DefaultX509Configuration { + // tag::springSecurity[] + @Bean + fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? { + // @formatter:off + http { + authorizeHttpRequests { + authorize(anyRequest, authenticated) + } + x509 { } + } + // @formatter:on + return http.build() + } + // end::springSecurity[] + + @Bean + fun userDetailsService(): UserDetailsService { + // @formatter:off + val user = User + .withUsername("rod") + .password("password") + .roles("USER") + .build() + // @formatter:on + return InMemoryUserDetailsManager(user) + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/X509ConfigurationTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/X509ConfigurationTests.kt new file mode 100644 index 0000000000..edaf503039 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/servlet/authentication/servletx509config/X509ConfigurationTests.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.kt.docs.servlet.authentication.servlet509config + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.config.test.SpringTestContext +import org.springframework.security.config.test.SpringTestContextExtension +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated +import org.springframework.security.web.authentication.preauth.x509.X509TestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +/** + * Tests [CustomX509Configuration]. + * + * @author Rob Winch + */ +@ExtendWith(SpringTestContextExtension::class) +class X509ConfigurationTests { + @JvmField + val spring: SpringTestContext = SpringTestContext(this) + + @Autowired + var mockMvc: MockMvc? = null + + @Test + @Throws(Exception::class) + fun x509WhenDefaultX509Configuration() { + this.spring.register(DefaultX509Configuration::class.java, Http200Controller::class.java).autowire() + // @formatter:off + this.mockMvc!!.perform(get("/").with(SecurityMockMvcRequestPostProcessors.x509("rod.cer"))) + .andExpect(status().isOk()) + .andExpect(authenticated().withUsername("rod")) + // @formatter:on + } + + @Test + @Throws(Exception::class) + fun x509WhenCustomX509Configuration() { + this.spring.register(CustomX509Configuration::class.java, Http200Controller::class.java).autowire() + val certificate = X509TestUtils.buildTestCertificate() + // @formatter:off + this.mockMvc!!.perform(get("/").with(SecurityMockMvcRequestPostProcessors.x509(certificate))) + .andExpect(status().isOk()) + .andExpect(authenticated().withUsername("luke@monkeymachine")) + // @formatter:on + } + + @RestController + internal class Http200Controller { + @GetMapping("/**") + fun ok(): String { + return "ok" + } + } +} diff --git a/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.xml b/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.xml new file mode 100644 index 0000000000..cc2772e34b --- /dev/null +++ b/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/CustomX509Configuration.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.xml b/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.xml new file mode 100644 index 0000000000..62621d1cab --- /dev/null +++ b/docs/src/test/resources/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + From b0cecb37d20468b7b9f01176951580138354c0aa Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Fri, 18 Apr 2025 13:11:17 +0300 Subject: [PATCH 337/504] Replace deprecated #check calls with #authorize Closes gh-16936 Signed-off-by: Evgeniy Cheban --- .../AuthorizeHttpRequestsConfigurerTests.java | 6 ++++- .../authorization/AuthorizationManager.java | 8 +++---- .../ObservationAuthorizationManager.java | 23 +++++++++++++++---- .../ObservationAuthorizationManagerTests.java | 5 +++- ...MatcherDelegatingAuthorizationManager.java | 18 +++++++++++++-- ...MatcherDelegatingAuthorizationManager.java | 18 +++++++++++++-- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index 057deea40c..7d57cae201 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,6 +85,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doCallRealMethod; @@ -153,6 +154,7 @@ public class AuthorizeHttpRequestsConfigurerTests { @Test public void configureMvcMatcherAccessAuthorizationManagerWhenNotNullThenVerifyUse() throws Exception { CustomAuthorizationManagerConfig.authorizationManager = mock(AuthorizationManager.class); + given(CustomAuthorizationManagerConfig.authorizationManager.authorize(any(), any())).willCallRealMethod(); this.spring.register(CustomAuthorizationManagerConfig.class, BasicController.class).autowire(); this.mvc.perform(get("/")).andExpect(status().isOk()); verify(CustomAuthorizationManagerConfig.authorizationManager).check(any(), any()); @@ -161,6 +163,8 @@ public class AuthorizeHttpRequestsConfigurerTests { @Test public void configureNoParameterMvcMatcherAccessAuthorizationManagerWhenNotNullThenVerifyUse() throws Exception { CustomAuthorizationManagerNoParameterConfig.authorizationManager = mock(AuthorizationManager.class); + given(CustomAuthorizationManagerNoParameterConfig.authorizationManager.authorize(any(), any())) + .willCallRealMethod(); this.spring.register(CustomAuthorizationManagerNoParameterConfig.class, BasicController.class).autowire(); this.mvc.perform(get("/")).andExpect(status().isOk()); verify(CustomAuthorizationManagerNoParameterConfig.authorizationManager).check(any(), any()); diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/AuthorizationManager.java index 758abce2c7..b039068b22 100644 --- a/core/src/main/java/org/springframework/security/authorization/AuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/AuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,9 +39,9 @@ public interface AuthorizationManager { * @throws AccessDeniedException if access is not granted */ default void verify(Supplier authentication, T object) { - AuthorizationDecision decision = check(authentication, object); - if (decision != null && !decision.isGranted()) { - throw new AuthorizationDeniedException("Access Denied", decision); + AuthorizationResult result = authorize(authentication, object); + if (result != null && !result.isGranted()) { + throw new AuthorizationDeniedException("Access Denied", result); } } diff --git a/core/src/main/java/org/springframework/security/authorization/ObservationAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/ObservationAuthorizationManager.java index 0494dbfecb..2c4a785f30 100644 --- a/core/src/main/java/org/springframework/security/authorization/ObservationAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/ObservationAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,6 +67,19 @@ public final class ObservationAuthorizationManager @Deprecated @Override public AuthorizationDecision check(Supplier authentication, T object) { + AuthorizationResult result = authorize(authentication, object); + if (result == null) { + return null; + } + if (result instanceof AuthorizationDecision decision) { + return decision; + } + throw new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type AuthorizationDecision"); + } + + @Override + public AuthorizationResult authorize(Supplier authentication, T object) { AuthorizationObservationContext context = new AuthorizationObservationContext<>(object); Supplier wrapped = () -> { context.setAuthentication(authentication.get()); @@ -74,13 +87,13 @@ public final class ObservationAuthorizationManager }; Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry).start(); try (Observation.Scope scope = observation.openScope()) { - AuthorizationDecision decision = this.delegate.check(wrapped, object); - context.setAuthorizationResult(decision); - if (decision != null && !decision.isGranted()) { + AuthorizationResult result = this.delegate.authorize(wrapped, object); + context.setAuthorizationResult(result); + if (result != null && !result.isGranted()) { observation.error(new AccessDeniedException( this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access Denied"))); } - return decision; + return result; } catch (Throwable ex) { observation.error(ex); diff --git a/core/src/test/java/org/springframework/security/authorization/ObservationAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/ObservationAuthorizationManagerTests.java index 1921f7dc1a..bb2ccd8faa 100644 --- a/core/src/test/java/org/springframework/security/authorization/ObservationAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/ObservationAuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,6 +74,7 @@ public class ObservationAuthorizationManagerTests { void verifyWhenDefaultsThenObserves() { given(this.handler.supportsContext(any())).willReturn(true); given(this.authorizationManager.check(any(), any())).willReturn(this.grant); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); this.tested.verify(this.token, this.object); ArgumentCaptor captor = ArgumentCaptor.forClass(Observation.Context.class); verify(this.handler).onStart(captor.capture()); @@ -92,6 +93,7 @@ public class ObservationAuthorizationManagerTests { this.tested.setMessageSource(source); given(this.handler.supportsContext(any())).willReturn(true); given(this.authorizationManager.check(any(), any())).willReturn(this.deny); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); given(source.getMessage(eq("AbstractAccessDecisionManager.accessDenied"), any(), any(), any())) .willReturn("accessDenied"); assertThatExceptionOfType(AccessDeniedException.class) @@ -116,6 +118,7 @@ public class ObservationAuthorizationManagerTests { ((Supplier) invocation.getArgument(0)).get(); return this.grant; }); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); this.tested.verify(this.token, this.object); ArgumentCaptor captor = ArgumentCaptor.forClass(Observation.Context.class); verify(this.handler).onStart(captor.capture()); diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java index e7ff32718a..c24bb1b7b5 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java @@ -30,6 +30,7 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationMana import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.messaging.util.matcher.MessageMatcher; @@ -63,11 +64,24 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho * @return an {@link AuthorizationDecision}. If there is no {@link MessageMatcher} * matching the message, or the {@link AuthorizationManager} could not decide, then * null is returned - * @deprecated please use {@link #authorize(Supplier, Object)} instead + * @deprecated please use {@link #authorize(Supplier, Message)} instead */ @Deprecated @Override public AuthorizationDecision check(Supplier authentication, Message message) { + AuthorizationResult result = authorize(authentication, message); + if (result == null) { + return null; + } + if (result instanceof AuthorizationDecision decision) { + return decision; + } + throw new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type AuthorizationDecision"); + } + + @Override + public AuthorizationResult authorize(Supplier authentication, Message message) { if (this.logger.isTraceEnabled()) { this.logger.trace(LogMessage.format("Authorizing message")); } @@ -79,7 +93,7 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho if (this.logger.isTraceEnabled()) { this.logger.trace(LogMessage.format("Checking authorization on message using %s", manager)); } - return manager.check(authentication, authorizationContext); + return manager.authorize(authentication, authorizationContext); } } this.logger.trace("Abstaining since did not find matching MessageMatcher"); diff --git a/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java b/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java index b01ab43bbd..de660a3f97 100644 --- a/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java +++ b/web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java @@ -30,6 +30,7 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationMana import org.springframework.security.authorization.AuthorityAuthorizationManager; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.web.util.UrlUtils; @@ -69,11 +70,24 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho * @return an {@link AuthorizationDecision}. If there is no {@link RequestMatcher} * matching the request, or the {@link AuthorizationManager} could not decide, then * null is returned - * @deprecated please use {@link #authorize(Supplier, Object)} instead + * @deprecated please use {@link #authorize(Supplier, HttpServletRequest)} instead */ @Deprecated @Override public AuthorizationDecision check(Supplier authentication, HttpServletRequest request) { + AuthorizationResult result = authorize(authentication, request); + if (result == null) { + return null; + } + if (result instanceof AuthorizationDecision decision) { + return decision; + } + throw new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type AuthorizationDecision"); + } + + @Override + public AuthorizationResult authorize(Supplier authentication, HttpServletRequest request) { if (this.logger.isTraceEnabled()) { this.logger.trace(LogMessage.format("Authorizing %s", requestLine(request))); } @@ -87,7 +101,7 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho this.logger.trace( LogMessage.format("Checking authorization on %s using %s", requestLine(request), manager)); } - return manager.check(authentication, + return manager.authorize(authentication, new RequestAuthorizationContext(request, matchResult.getVariables())); } } From 092bbfc8e7e8d507e50908044b10e65d6a156472 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Thu, 24 Apr 2025 23:54:37 +0300 Subject: [PATCH 338/504] ReactiveAuthorizationManager replace deprecated #check calls with #authorize Closes gh-16936 Signed-off-by: Evgeniy Cheban --- ...servationReactiveAuthorizationManager.java | 19 +++++++++++++---- .../ReactiveAuthorizationManager.java | 6 +++--- ...tionReactiveAuthorizationManagerTests.java | 5 ++++- ...geMatcherReactiveAuthorizationManager.java | 18 +++++++++++++--- ...cherReactiveAuthorizationManagerTests.java | 6 +++++- ...elegatingReactiveAuthorizationManager.java | 21 +++++++++++++++---- ...tingReactiveAuthorizationManagerTests.java | 4 +++- 7 files changed, 62 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManager.java index a9d77c641b..0ef9b3a4be 100644 --- a/core/src/main/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,6 +62,17 @@ public final class ObservationReactiveAuthorizationManager @Deprecated @Override public Mono check(Mono authentication, T object) { + return authorize(authentication, object).flatMap((result) -> { + if (result instanceof AuthorizationDecision decision) { + return Mono.just(decision); + } + return Mono.error(new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type Mono")); + }); + } + + @Override + public Mono authorize(Mono authentication, T object) { AuthorizationObservationContext context = new AuthorizationObservationContext<>(object); Mono wrapped = authentication.map((auth) -> { context.setAuthentication(auth); @@ -71,9 +82,9 @@ public final class ObservationReactiveAuthorizationManager Observation observation = Observation.createNotStarted(this.convention, () -> context, this.registry) .parentObservation(contextView.getOrDefault(ObservationThreadLocalAccessor.KEY, null)) .start(); - return this.delegate.check(wrapped, object).doOnSuccess((decision) -> { - context.setAuthorizationResult(decision); - if (decision == null || !decision.isGranted()) { + return this.delegate.authorize(wrapped, object).doOnSuccess((result) -> { + context.setAuthorizationResult(result); + if (result == null || !result.isGranted()) { observation.error(new AccessDeniedException("Access Denied")); } observation.stop(); diff --git a/core/src/main/java/org/springframework/security/authorization/ReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/ReactiveAuthorizationManager.java index 05662737d1..860208c6f5 100644 --- a/core/src/main/java/org/springframework/security/authorization/ReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/ReactiveAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,8 +50,8 @@ public interface ReactiveAuthorizationManager { */ default Mono verify(Mono authentication, T object) { // @formatter:off - return check(authentication, object) - .filter(AuthorizationDecision::isGranted) + return authorize(authentication, object) + .filter(AuthorizationResult::isGranted) .switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Access Denied")))) .flatMap((decision) -> Mono.empty()); // @formatter:on diff --git a/core/src/test/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManagerTests.java index 34b0533a26..d3eb935cc7 100644 --- a/core/src/test/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/ObservationReactiveAuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,6 +70,7 @@ public class ObservationReactiveAuthorizationManagerTests { void verifyWhenDefaultsThenObserves() { given(this.handler.supportsContext(any())).willReturn(true); given(this.authorizationManager.check(any(), any())).willReturn(Mono.just(this.grant)); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); this.tested.verify(this.token, this.object).block(); ArgumentCaptor captor = ArgumentCaptor.forClass(Observation.Context.class); verify(this.handler).onStart(captor.capture()); @@ -86,6 +87,7 @@ public class ObservationReactiveAuthorizationManagerTests { void verifyWhenErrorsThenObserves() { given(this.handler.supportsContext(any())).willReturn(true); given(this.authorizationManager.check(any(), any())).willReturn(Mono.just(this.deny)); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); assertThatExceptionOfType(AccessDeniedException.class) .isThrownBy(() -> this.tested.verify(this.token, this.object).block()); ArgumentCaptor captor = ArgumentCaptor.forClass(Observation.Context.class); @@ -106,6 +108,7 @@ public class ObservationReactiveAuthorizationManagerTests { ((Mono) invocation.getArgument(0)).block(); return Mono.just(this.grant); }); + given(this.authorizationManager.authorize(any(), any())).willCallRealMethod(); this.tested.verify(this.token, this.object).block(); ArgumentCaptor captor = ArgumentCaptor.forClass(Observation.Context.class); verify(this.handler).onStart(captor.capture()); diff --git a/rsocket/src/main/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManager.java b/rsocket/src/main/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManager.java index fc7862f51e..9004633f9e 100644 --- a/rsocket/src/main/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManager.java +++ b/rsocket/src/main/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.rsocket.api.PayloadExchange; @@ -51,18 +52,29 @@ public final class PayloadExchangeMatcherReactiveAuthorizationManager } /** - * @deprecated please use {@link #authorize(Mono, Object)} instead + * @deprecated please use {@link #authorize(Mono, PayloadExchange)} instead */ @Deprecated @Override public Mono check(Mono authentication, PayloadExchange exchange) { + return authorize(authentication, exchange).flatMap((result) -> { + if (result instanceof AuthorizationDecision decision) { + return Mono.just(decision); + } + return Mono.error(new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type Mono")); + }); + } + + @Override + public Mono authorize(Mono authentication, PayloadExchange exchange) { return Flux.fromIterable(this.mappings) .concatMap((mapping) -> mapping.getMatcher() .matches(exchange) .filter(PayloadExchangeMatcher.MatchResult::isMatch) .map(MatchResult::getVariables) .flatMap((variables) -> mapping.getEntry() - .check(authentication, new PayloadExchangeAuthorizationContext(exchange, variables)))) + .authorize(authentication, new PayloadExchangeAuthorizationContext(exchange, variables)))) .next() .switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false))); } diff --git a/rsocket/src/test/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManagerTests.java b/rsocket/src/test/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManagerTests.java index 4f8041aeb4..c0b14cb835 100644 --- a/rsocket/src/test/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManagerTests.java +++ b/rsocket/src/test/java/org/springframework/security/rsocket/authorization/PayloadExchangeMatcherReactiveAuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests { public void checkWhenGrantedThenGranted() { AuthorizationDecision expected = new AuthorizationDecision(true); given(this.authz.check(any(), any())).willReturn(Mono.just(expected)); + given(this.authz.authorize(any(), any())).willCallRealMethod(); PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager .builder() .add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz)) @@ -64,6 +65,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests { public void checkWhenDeniedThenDenied() { AuthorizationDecision expected = new AuthorizationDecision(false); given(this.authz.check(any(), any())).willReturn(Mono.just(expected)); + given(this.authz.authorize(any(), any())).willCallRealMethod(); PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager .builder() .add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz)) @@ -75,6 +77,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests { public void checkWhenFirstMatchThenSecondUsed() { AuthorizationDecision expected = new AuthorizationDecision(true); given(this.authz.check(any(), any())).willReturn(Mono.just(expected)); + given(this.authz.authorize(any(), any())).willCallRealMethod(); PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager .builder() .add(new PayloadExchangeMatcherEntry<>(PayloadExchangeMatchers.anyExchange(), this.authz)) @@ -87,6 +90,7 @@ public class PayloadExchangeMatcherReactiveAuthorizationManagerTests { public void checkWhenSecondMatchThenSecondUsed() { AuthorizationDecision expected = new AuthorizationDecision(true); given(this.authz2.check(any(), any())).willReturn(Mono.just(expected)); + given(this.authz2.authorize(any(), any())).willCallRealMethod(); PayloadExchangeMatcherReactiveAuthorizationManager manager = PayloadExchangeMatcherReactiveAuthorizationManager .builder() .add(new PayloadExchangeMatcherEntry<>((e) -> PayloadExchangeMatcher.MatchResult.notMatch(), this.authz)) diff --git a/web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java b/web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java index ebdb2b8ccb..e245ce0466 100644 --- a/web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java +++ b/web/src/main/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.log.LogMessage; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult; @@ -35,6 +36,7 @@ import org.springframework.web.server.ServerWebExchange; /** * @author Rob Winch * @author Mathieu Ouellet + * @author Evgeniy Cheban * @since 5.0 */ public final class DelegatingReactiveAuthorizationManager implements ReactiveAuthorizationManager { @@ -49,11 +51,22 @@ public final class DelegatingReactiveAuthorizationManager implements ReactiveAut } /** - * @deprecated please use {@link #authorize(Mono, Object)} instead + * @deprecated please use {@link #authorize(Mono, ServerWebExchange)} instead */ @Deprecated @Override public Mono check(Mono authentication, ServerWebExchange exchange) { + return authorize(authentication, exchange).flatMap((result) -> { + if (result instanceof AuthorizationDecision decision) { + return Mono.just(decision); + } + return Mono.error(new IllegalArgumentException( + "Please call #authorize or ensure that the returned result is of type Mono")); + }); + } + + @Override + public Mono authorize(Mono authentication, ServerWebExchange exchange) { return Flux.fromIterable(this.mappings) .concatMap((mapping) -> mapping.getMatcher() .matches(exchange) @@ -63,10 +76,10 @@ public final class DelegatingReactiveAuthorizationManager implements ReactiveAut logger.debug(LogMessage.of(() -> "Checking authorization on '" + exchange.getRequest().getPath().pathWithinApplication() + "' using " + mapping.getEntry())); - return mapping.getEntry().check(authentication, new AuthorizationContext(exchange, variables)); + return mapping.getEntry().authorize(authentication, new AuthorizationContext(exchange, variables)); })) .next() - .defaultIfEmpty(new AuthorizationDecision(false)); + .switchIfEmpty(Mono.fromCallable(() -> new AuthorizationDecision(false))); } public static DelegatingReactiveAuthorizationManager.Builder builder() { diff --git a/web/src/test/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManagerTests.java b/web/src/test/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManagerTests.java index 8d916142d2..adab9bb717 100644 --- a/web/src/test/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManagerTests.java +++ b/web/src/test/java/org/springframework/security/web/server/authorization/DelegatingReactiveAuthorizationManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,6 +81,7 @@ public class DelegatingReactiveAuthorizationManagerTests { given(this.match1.matches(any())).willReturn(ServerWebExchangeMatcher.MatchResult.match()); given(this.delegate1.check(eq(this.authentication), any(AuthorizationContext.class))) .willReturn(Mono.just(this.decision)); + given(this.delegate1.authorize(eq(this.authentication), any(AuthorizationContext.class))).willCallRealMethod(); assertThat(this.manager.check(this.authentication, this.exchange).block()).isEqualTo(this.decision); verifyNoMoreInteractions(this.match2, this.delegate2); } @@ -91,6 +92,7 @@ public class DelegatingReactiveAuthorizationManagerTests { given(this.match2.matches(any())).willReturn(ServerWebExchangeMatcher.MatchResult.match()); given(this.delegate2.check(eq(this.authentication), any(AuthorizationContext.class))) .willReturn(Mono.just(this.decision)); + given(this.delegate2.authorize(eq(this.authentication), any(AuthorizationContext.class))).willCallRealMethod(); assertThat(this.manager.check(this.authentication, this.exchange).block()).isEqualTo(this.decision); verifyNoMoreInteractions(this.delegate1); } From 040ffe17e590bcd3c08032b33424dd3aea513f1d Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:19:37 -0500 Subject: [PATCH 339/504] Add SubjectX500PrincipalExtractor to Whats New Issue gh-16984 --- docs/modules/ROOT/pages/whats-new.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index 1f86df6989..79f7ba57ff 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -3,3 +3,7 @@ Spring Security 7.0 provides a number of new features. Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix. + +== Web + +* Added javadoc:org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor[] From c1492f0e4e6ee6bc30fdf94451f1dc9cbde6bc8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:11:19 +0000 Subject: [PATCH 340/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 9f487ad0bc3ca9aafa7a3fc156b83fa5dbe2cbc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:11:55 +0000 Subject: [PATCH 341/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 34ec5fd7a40ee16f4ac67543d0615b10cc2f3b59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:31:29 +0000 Subject: [PATCH 342/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 1b2ac8567e3ba93041483adeeb4c0a8fa7f8fe4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:31:36 +0000 Subject: [PATCH 343/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a716c7468a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From effe682fc4388f3857bfb29c65bce6cb9a208820 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:35:50 +0000 Subject: [PATCH 344/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 46254e01fba83b7ced2192ff87bf8b8bb9c3cfa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:36:23 +0000 Subject: [PATCH 345/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 043464fd3d7ed5f397b6145f5bb26a89f900e40a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:47:51 +0000 Subject: [PATCH 346/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.2.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.2.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.2/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.2) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.2.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..6699e8e4dc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.2.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 5130cbb99f2c1a3ea0a3be06691e2767eb8c7809 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:48:15 +0000 Subject: [PATCH 347/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..ddf324f57b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 1f57df6caa2ce5ff69723a95eb4634c8b5935e6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 03:37:16 +0000 Subject: [PATCH 348/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..f8ffc67025 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From aca7c4f5c414fc91c156ada53153b0def96cc432 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 03:52:13 +0000 Subject: [PATCH 349/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..0475e149f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 29866df7cf99aa69e69d070a72013cbb6ef20f86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 03:52:20 +0000 Subject: [PATCH 350/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From e34c5e73e1d53a7e2a7c5b372c708251ef89c4b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 04:01:56 +0000 Subject: [PATCH 351/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 07bb38e5e55ee786f94ca81a4999d6fc8a90db67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 04:09:40 +0000 Subject: [PATCH 352/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..98c4e279d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 3e6eda579fc78c74fcdab9f8c94d22106c9e96cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 04:10:04 +0000 Subject: [PATCH 353/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From ebdd6c22a89e5b605b0540857f7824754922e56d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 15:07:59 +0000 Subject: [PATCH 354/504] Release 6.5.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 50aca0de35..4be2d2838f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.1-SNAPSHOT +version=6.5.1 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From ae1537b409a9a4c2baf0b13ddec99fcad466bf49 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 15:08:20 +0000 Subject: [PATCH 355/504] Release 6.3.10 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 65a1331cd8..214b134b2b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ springBootVersion=3.1.1 -version=6.3.10-SNAPSHOT +version=6.3.10 samplesBranch=6.3.x org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 30056be789522cca994eb6a939d85736eb774696 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 15:08:24 +0000 Subject: [PATCH 356/504] Release 6.4.7 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2d5886cf13..3a02d4a776 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.7-SNAPSHOT +version=6.4.7 samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 449c7a8419d8806d843e8983d1c1a0a26a8eb6f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 15:34:45 +0000 Subject: [PATCH 357/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 214b134b2b..bae90d6377 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ springBootVersion=3.1.1 -version=6.3.10 +version=6.3.11-SNAPSHOT samplesBranch=6.3.x org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 726b9a80a0530a49e192e326f9bc760824223209 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 18:46:36 +0000 Subject: [PATCH 358/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3a02d4a776..a189ce8b53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.4.7 +version=6.4.8-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 063ee71e0d21ba20eadaac77bc6c6a887b57a7e4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 18:47:03 +0000 Subject: [PATCH 359/504] Next development version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4be2d2838f..b8c26375bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # springBootVersion=3.3.3 -version=6.5.1 +version=6.5.2-SNAPSHOT samplesBranch=main org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError org.gradle.parallel=true From 602aa1c46c72e4c18f585850936ed1e8f72f1750 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:30:27 +0000 Subject: [PATCH 360/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..98c4e279d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From bd31a4082481421e657470fb6064ec30d43abd44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:32:10 +0000 Subject: [PATCH 361/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..f8ffc67025 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From d871f7f295efac4dbf640c43a64edc50f7b48cfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:33:42 +0000 Subject: [PATCH 362/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 854375e3901d053745f794907bbeba69304d7762 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:37:19 +0000 Subject: [PATCH 363/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a716c7468a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From f0c34eb39deeb3123f35cf67c3b42a8b5dbe0a94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:40:53 +0000 Subject: [PATCH 364/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 9f1ba97bb09bfb8e9c5f2a537ea371fac2c224bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:43:53 +0000 Subject: [PATCH 365/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From c2ecc8b5387a62d0a712b00103c1a6ee425058fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:47:07 +0000 Subject: [PATCH 366/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..ddf324f57b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From d933f1b88195378e7be6731da43da333b071282c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:47:26 +0000 Subject: [PATCH 367/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From fce40bc3ed5f2dafbe43272645db26341f1a789c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:48:38 +0000 Subject: [PATCH 368/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.2.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.2.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.2/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.2) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.2.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..6699e8e4dc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.2.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From f69aad2e547c7088ca33a5fe65f052ec95f4101e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:49:39 +0000 Subject: [PATCH 369/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From bbc6fb3ac211037b9920a6063b4d68632a7aa9f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:01:36 +0000 Subject: [PATCH 370/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 605d497ef6e88786f7a51d7b7a0ca3bc2ae284a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:01:49 +0000 Subject: [PATCH 371/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From cdd71d2bd58e9874b604938ab91f0acabfa7b036 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:02:08 +0000 Subject: [PATCH 372/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..0475e149f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From d962701375ad360edd2f0dd3cddedb45d641b8b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:02:21 +0000 Subject: [PATCH 373/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From b2325e41764e0ea2ea04bcfd2c345c610edf8bf7 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 8 May 2025 16:21:09 -0500 Subject: [PATCH 374/504] Add OAuth Support for HTTP Interface Client Closes gh-16858 --- docs/modules/ROOT/nav.adoc | 2 + .../integrations/rest/http-interface.adoc | 66 +++++++++++ .../oauth2/client/authorized-clients.adoc | 5 + docs/modules/ROOT/pages/whats-new.adoc | 1 + docs/spring-security-docs.gradle | 3 + .../rest/clientregistrationid/User.java | 28 +++++ .../clientregistrationid/UserService.java | 36 ++++++ ...HttpInterfaceIntegrationConfiguration.java | 67 +++++++++++ ...nterfaceIntegrationConfigurationTests.java | 73 ++++++++++++ ...nterfaceIntegrationConfigurationTests.java | 75 ++++++++++++ ...HttpInterfaceIntegrationConfiguration.java | 69 +++++++++++ .../rest/clientregistrationid/User.kt | 29 +++++ .../rest/clientregistrationid/UserService.kt | 35 ++++++ ...ntHttpInterfaceIntegrationConfiguration.kt | 65 +++++++++++ ...pInterfaceIntegrationConfigurationTests.kt | 75 ++++++++++++ ...pInterfaceIntegrationConfigurationTests.kt | 78 +++++++++++++ ...ntHttpInterfaceIntegrationConfiguration.kt | 72 ++++++++++++ .../annotation/ClientRegistrationId.java | 58 ++++++++++ .../oauth2/client/web/ClientAttributes.java | 69 +++++++++++ .../client/ClientRegistrationIdProcessor.java | 51 +++++++++ ...AttributeClientRegistrationIdResolver.java | 11 +- ...2RestClientHttpServiceGroupConfigurer.java | 67 +++++++++++ ...uthorizedClientExchangeFilterFunction.java | 12 +- ...uthorizedClientExchangeFilterFunction.java | 8 +- ...h2WebClientHttpServiceGroupConfigurer.java | 92 +++++++++++++++ ...verClientRegistrationIdProcessorTests.java | 108 ++++++++++++++++++ ...egistrationIdProcessorRestClientTests.java | 60 ++++++++++ .../ClientRegistrationIdProcessorTests.java | 94 +++++++++++++++ ...RegistrationIdProcessorWebClientTests.java | 82 +++++++++++++ ...ClientHttpServiceGroupConfigurerTests.java | 89 +++++++++++++++ ...ClientHttpServiceGroupConfigurerTests.java | 89 +++++++++++++++ 31 files changed, 1647 insertions(+), 22 deletions(-) create mode 100644 docs/modules/ROOT/pages/features/integrations/rest/http-interface.adoc create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/User.java create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/UserService.java create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.java create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.java create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.java create mode 100644 docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.java create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/User.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/UserService.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.kt create mode 100644 docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/annotation/ClientRegistrationId.java create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ClientAttributes.java create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessor.java create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurer.java create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurer.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/AbstractMockServerClientRegistrationIdProcessorTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorRestClientTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorWebClientTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurerTests.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurerTests.java diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 24ca536e13..c113bbc609 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -19,6 +19,8 @@ *** xref:features/exploits/headers.adoc[HTTP Headers] *** xref:features/exploits/http.adoc[HTTP Requests] ** xref:features/integrations/index.adoc[Integrations] +*** REST Client +**** xref:features/integrations/rest/http-interface.adoc[HTTP Interface Integration] *** xref:features/integrations/cryptography.adoc[Cryptography] *** xref:features/integrations/data.adoc[Spring Data] *** xref:features/integrations/concurrency.adoc[Java's Concurrency APIs] diff --git a/docs/modules/ROOT/pages/features/integrations/rest/http-interface.adoc b/docs/modules/ROOT/pages/features/integrations/rest/http-interface.adoc new file mode 100644 index 0000000000..535ae27bdb --- /dev/null +++ b/docs/modules/ROOT/pages/features/integrations/rest/http-interface.adoc @@ -0,0 +1,66 @@ += HTTP Interface Integration + +Spring Security's OAuth Support can integrate with `RestClient` and `WebClient` {spring-framework-reference-url}/integration/rest-clients.html[HTTP Interface based REST Clients]. + + +[[configuration]] +== Configuration +After xref:features/integrations/rest/http-interface.adoc#configuration-restclient[RestClient] or xref:features/integrations/rest/http-interface.adoc#configuration-webclient[WebClient] specific configuration, usage of xref:features/integrations/rest/http-interface.adoc[] only requires adding a xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] to methods that require OAuth. + +Since the presense of xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] determines if and how the OAuth token will be resolved, it is safe to add Spring Security's OAuth support any configuration. + +[[configuration-restclient]] +=== RestClient Configuration + +Spring Security's OAuth Support can integrate with {spring-framework-reference-url}/integration/rest-clients.html[HTTP Interface based REST Clients] backed by RestClient. +The first step is to xref:servlet/oauth2/client/core.adoc#oauth2Client-authorized-manager-provider[create an `OAuthAuthorizedClientManager` Bean]. + +Next you must configure `HttpServiceProxyFactory` and `RestClient` to be aware of xref:./http-interface.adoc#client-registration-id[@ClientRegistrationId] +To simplify this configuration, use javadoc:org.springframework.security.oauth2.client.web.client.support.OAuth2RestClientHttpServiceGroupConfigurer[]. + +include-code::./RestClientHttpInterfaceIntegrationConfiguration[tag=config,indent=0] + +The configuration: + +- Adds xref:features/integrations/rest/http-interface.adoc#client-registration-id-processor[`ClientRegistrationIdProcessor`] to {spring-framework-reference-url}/integration/rest-clients.html#rest-http-interface[`HttpServiceProxyFactory`] +- Adds xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-rest-client[`OAuth2ClientHttpRequestInterceptor`] to the `RestClient` + +[[configuration-webclient]] +=== WebClient Configuration + +Spring Security's OAuth Support can integrate with {spring-framework-reference-url}/integration/rest-clients.html[HTTP Interface based REST Clients] backed by `WebClient`. +The first step is to xref:reactive/oauth2/client/core.adoc#oauth2Client-authorized-manager-provider[create an `ReactiveOAuthAuthorizedClientManager` Bean]. + +Next you must configure `HttpServiceProxyFactory` and `WebRestClient` to be aware of xref:./http-interface.adoc#client-registration-id[@ClientRegistrationId] +To simplify this configuration, use javadoc:org.springframework.security.oauth2.client.web.reactive.function.client.support.OAuth2WebClientHttpServiceGroupConfigurer[]. + +include-code::./ServerWebClientHttpInterfaceIntegrationConfiguration[tag=config,indent=0] + +The configuration: + +- Adds xref:features/integrations/rest/http-interface.adoc#client-registration-id-processor[`ClientRegistrationIdProcessor`] to {spring-framework-reference-url}/integration/rest-clients.html#rest-http-interface[`HttpServiceProxyFactory`] +- Adds xref:reactive/oauth2/client/authorized-clients.adoc#oauth2-client-web-client[`ServerOAuth2AuthorizedClientExchangeFilterFunction`] to the `WebClient` + + +[[client-registration-id]] +== @ClientRegistrationId + +You can add the javadoc:org.springframework.security.oauth2.client.annotation.ClientRegistrationId[] on the HTTP Interface to specify which javadoc:org.springframework.security.oauth2.client.registration.ClientRegistration[] to use. + +include-code::./UserService[tag=getAuthenticatedUser] + +The xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] will be processed by xref:features/integrations/rest/http-interface.adoc#client-registration-id-processor[`ClientRegistrationIdProcessor`] + +[[client-registration-id-processor]] +== `ClientRegistrationIdProcessor` + +The xref:features/integrations/rest/http-interface.adoc#configuration[configured] javadoc:org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor[] will: + +- Automatically invoke javadoc:org.springframework.security.oauth2.client.web.ClientAttributes#clientRegistrationId(java.lang.String)[] for each xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`]. +- This adds the javadoc:org.springframework.security.oauth2.client.registration.ClientRegistration#getId()[] to the attributes + +The `id` is then processed by: + +- `OAuth2ClientHttpRequestInterceptor` for xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-rest-client[RestClient Integration] +- xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-web-client[`ServletOAuth2AuthorizedClientExchangeFilterFunction`] (servlets) or xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-web-client[`ServerOAuth2AuthorizedClientExchangeFilterFunction`] (reactive environments) for `WebClient`. + diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc index 8864e4e7db..aa721f1413 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc @@ -495,6 +495,11 @@ class RestClientConfig { ---- ===== +[[oauth2-client-rest-client-interface]] +=== HTTP Interface Integration + +Spring Security's OAuth support integrates with xref:features/integrations/rest/http-interface.adoc[]. + [[oauth2-client-web-client]] == [[oauth2Client-webclient-servlet]]WebClient Integration for Servlet Environments diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index 79f7ba57ff..140efdf0d4 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -7,3 +7,4 @@ Below are the highlights of the release, or you can view https://github.com/spri == Web * Added javadoc:org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor[] +* Added OAuth2 Support for xref:features/integrations/rest/http-interface.adoc[HTTP Interface Integration] diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index ec459fc115..680ab725e9 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -39,6 +39,8 @@ dependencies { testImplementation project(':spring-security-config') testImplementation project(path : ':spring-security-config', configuration : 'tests') testImplementation project(':spring-security-test') + testImplementation project(':spring-security-oauth2-client') + testImplementation 'com.squareup.okhttp3:mockwebserver' testImplementation 'com.unboundid:unboundid-ldapsdk' testImplementation libs.webauthn4j.core testImplementation 'org.jetbrains.kotlin:kotlin-reflect' @@ -49,6 +51,7 @@ dependencies { testImplementation 'org.springframework:spring-webmvc' testImplementation 'jakarta.servlet:jakarta.servlet-api' + testImplementation 'io.mockk:mockk' testImplementation "org.junit.jupiter:junit-jupiter-api" testImplementation "org.junit.jupiter:junit-jupiter-params" testImplementation "org.junit.jupiter:junit-jupiter-engine" diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/User.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/User.java new file mode 100644 index 0000000000..08efa3bfef --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/User.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.clientregistrationid; + +/** + * A user. + * @param login + * @param id + * @param name + * @author Rob Winch + * @see UserService + */ +public record User(String login, int id, String name) { +} diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/UserService.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/UserService.java new file mode 100644 index 0000000000..f0088f887b --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/clientregistrationid/UserService.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.clientregistrationid; + +import org.springframework.security.oauth2.client.annotation.ClientRegistrationId; +import org.springframework.web.service.annotation.GetExchange; +import org.springframework.web.service.annotation.HttpExchange; + +/** + * Demonstrates a service for {@link ClientRegistrationId} and HTTP Interface clients. + * @author Rob Winch + */ +@HttpExchange +public interface UserService { + + // tag::getAuthenticatedUser[] + @GetExchange("/user") + @ClientRegistrationId("github") + User getAuthenticatedUser(); + // end::getAuthenticatedUser[] + +} diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.java new file mode 100644 index 0000000000..73d8b37ff0 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.configurationrestclient; + +import okhttp3.mockwebserver.MockWebServer; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.docs.features.integrations.rest.clientregistrationid.UserService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.support.OAuth2RestClientHttpServiceGroupConfigurer; +import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer; +import org.springframework.web.service.registry.ImportHttpServices; + +import static org.mockito.Mockito.mock; + +/** + * Documentation for {@link OAuth2RestClientHttpServiceGroupConfigurer}. + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@ImportHttpServices(types = UserService.class) +public class RestClientHttpInterfaceIntegrationConfiguration { + + // tag::config[] + @Bean + OAuth2RestClientHttpServiceGroupConfigurer securityConfigurer( + OAuth2AuthorizedClientManager manager) { + return OAuth2RestClientHttpServiceGroupConfigurer.from(manager); + } + // end::config[] + + @Bean + OAuth2AuthorizedClientManager authorizedClientManager() { + return mock(OAuth2AuthorizedClientManager.class); + } + + @Bean + RestClientHttpServiceGroupConfigurer groupConfigurer(MockWebServer server) { + return groups -> { + + groups + .forEachClient((group, builder) -> builder + .baseUrl(server.url("").toString()) + .defaultHeader("Accept", "application/vnd.github.v3+json")); + }; + } + + @Bean + MockWebServer mockServer() { + return new MockWebServer(); + } +} diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.java new file mode 100644 index 0000000000..5823aa90da --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.configurationrestclient; + +import java.time.Duration; +import java.time.Instant; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; +import org.springframework.security.docs.features.integrations.rest.clientregistrationid.UserService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +/** + * Tests RestClient configuration for HTTP Interface clients. + * @author Rob Winch + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = RestClientHttpInterfaceIntegrationConfiguration.class) +class RestClientHttpInterfaceIntegrationConfigurationTests { + + @Test + void getAuthenticatedUser(@Autowired MockWebServer webServer, @Autowired OAuth2AuthorizedClientManager authorizedClients, @Autowired UserService users) + throws InterruptedException { + ClientRegistration registration = CommonOAuth2Provider.GITHUB.getBuilder("github").clientId("github").build(); + + Instant issuedAt = Instant.now(); + Instant expiresAt = issuedAt.plus(Duration.ofMinutes(5)); + OAuth2AccessToken token = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "1234", + issuedAt, expiresAt); + OAuth2AuthorizedClient result = new OAuth2AuthorizedClient(registration, "rob", token); + given(authorizedClients.authorize(any())).willReturn(result); + + webServer.enqueue(new MockResponse().addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody( + """ + {"login": "rob_winch", "id": 1234, "name": "Rob Winch" } + """)); + + users.getAuthenticatedUser(); + + assertThat(webServer.takeRequest().getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer " + token.getTokenValue()); + } + +} diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.java new file mode 100644 index 0000000000..bdecbdc9b9 --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.configurationwebclient; + +import java.time.Duration; +import java.time.Instant; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; +import org.springframework.security.docs.features.integrations.rest.clientregistrationid.UserService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +/** + * Demonstrates configuring RestClient with interface based proxy clients. + * @author Rob Winch + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = ServerWebClientHttpInterfaceIntegrationConfiguration.class) +class ServerRestClientHttpInterfaceIntegrationConfigurationTests { + + @Test + void getAuthenticatedUser(@Autowired MockWebServer webServer, @Autowired ReactiveOAuth2AuthorizedClientManager authorizedClients, @Autowired UserService users) + throws InterruptedException { + ClientRegistration registration = CommonOAuth2Provider.GITHUB.getBuilder("github").clientId("github").build(); + + Instant issuedAt = Instant.now(); + Instant expiresAt = issuedAt.plus(Duration.ofMinutes(5)); + OAuth2AccessToken token = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "1234", + issuedAt, expiresAt); + OAuth2AuthorizedClient result = new OAuth2AuthorizedClient(registration, "rob", token); + given(authorizedClients.authorize(any())).willReturn(Mono.just(result)); + + webServer.enqueue(new MockResponse().addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody( + """ + {"login": "rob_winch", "id": 1234, "name": "Rob Winch" } + """)); + + users.getAuthenticatedUser(); + + assertThat(webServer.takeRequest().getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer " + token.getTokenValue()); + } + +} diff --git a/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.java b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.java new file mode 100644 index 0000000000..06e1970b5a --- /dev/null +++ b/docs/src/test/java/org/springframework/security/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.docs.features.integrations.rest.configurationwebclient; + +import okhttp3.mockwebserver.MockWebServer; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.docs.features.integrations.rest.clientregistrationid.UserService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.support.OAuth2RestClientHttpServiceGroupConfigurer; +import org.springframework.security.oauth2.client.web.reactive.function.client.support.OAuth2WebClientHttpServiceGroupConfigurer; +import org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer; +import org.springframework.web.service.registry.HttpServiceGroup; +import org.springframework.web.service.registry.ImportHttpServices; + +import static org.mockito.Mockito.mock; + +/** + * Documentation for {@link OAuth2RestClientHttpServiceGroupConfigurer}. + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@ImportHttpServices(types = UserService.class, clientType = HttpServiceGroup.ClientType.WEB_CLIENT) +public class ServerWebClientHttpInterfaceIntegrationConfiguration { + + // tag::config[] + @Bean + OAuth2WebClientHttpServiceGroupConfigurer securityConfigurer( + ReactiveOAuth2AuthorizedClientManager manager) { + return OAuth2WebClientHttpServiceGroupConfigurer.from(manager); + } + // end::config[] + + @Bean + ReactiveOAuth2AuthorizedClientManager authorizedClientManager() { + return mock(ReactiveOAuth2AuthorizedClientManager.class); + } + + @Bean + WebClientHttpServiceGroupConfigurer groupConfigurer(MockWebServer server) { + return groups -> { + String baseUrl = server.url("").toString(); + groups + .forEachClient((group, builder) -> builder + .baseUrl(baseUrl) + .defaultHeader("Accept", "application/vnd.github.v3+json")); + }; + } + + @Bean + MockWebServer mockServer() { + return new MockWebServer(); + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/User.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/User.kt new file mode 100644 index 0000000000..bb99882ab6 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/User.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid + + +/** + * A user. + * @param login + * @param id + * @param name + * @author Rob Winch + * @see UserService + */ +@JvmRecord +data class User(val login: String, val id: Int, val name: String) diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/UserService.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/UserService.kt new file mode 100644 index 0000000000..e9dde63d6a --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/clientregistrationid/UserService.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid + +import org.springframework.security.oauth2.client.annotation.ClientRegistrationId +import org.springframework.web.service.annotation.GetExchange +import org.springframework.web.service.annotation.HttpExchange + +/** + * Demonstrates a service for {@link ClientRegistrationId} and HTTP Interface clients. + * @author Rob Winch + */ +@HttpExchange +interface UserService { + + // tag::getAuthenticatedUser[] + @GetExchange("/user") + @ClientRegistrationId("github") + fun getAuthenticatedUser() : User + // end::getAuthenticatedUser[] +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.kt new file mode 100644 index 0000000000..d30e88a122 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfiguration.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.kt.docs.features.integrations.rest.configurationrestclient + +import okhttp3.mockwebserver.MockWebServer +import org.mockito.Mockito +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid.UserService +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.web.client.support.OAuth2RestClientHttpServiceGroupConfigurer +import org.springframework.web.client.RestClient +import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer +import org.springframework.web.service.registry.HttpServiceGroup +import org.springframework.web.service.registry.HttpServiceGroupConfigurer +import org.springframework.web.service.registry.HttpServiceGroupConfigurer.ClientCallback +import org.springframework.web.service.registry.ImportHttpServices + +/** + * Documentation for [OAuth2RestClientHttpServiceGroupConfigurer]. + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@ImportHttpServices(types = [UserService::class]) +class RestClientHttpInterfaceIntegrationConfiguration { + // tag::config[] + @Bean + fun securityConfigurer(manager: OAuth2AuthorizedClientManager): OAuth2RestClientHttpServiceGroupConfigurer { + return OAuth2RestClientHttpServiceGroupConfigurer.from(manager) + } + // end::config[] + + @Bean + fun authorizedClientManager(): OAuth2AuthorizedClientManager? { + return Mockito.mock(OAuth2AuthorizedClientManager::class.java) + } + + @Bean + fun groupConfigurer(server: MockWebServer): RestClientHttpServiceGroupConfigurer { + return RestClientHttpServiceGroupConfigurer { groups: HttpServiceGroupConfigurer.Groups -> + groups.forEachClient(ClientCallback { group: HttpServiceGroup, builder: RestClient.Builder -> + builder + .baseUrl(server.url("").toString()) + }) + } + } + + @Bean + fun mockServer(): MockWebServer { + return MockWebServer() + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.kt new file mode 100644 index 0000000000..85a395cd33 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationrestclient/RestClientHttpInterfaceIntegrationConfigurationTests.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.features.integrations.rest.configurationrestclient + +import io.mockk.every +import io.mockk.mockkObject +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider +import org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid.UserService +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager +import org.springframework.security.oauth2.core.OAuth2AccessToken +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.time.Duration +import java.time.Instant + +@ExtendWith(SpringExtension::class) +@ContextConfiguration(classes = [RestClientHttpInterfaceIntegrationConfiguration::class]) +internal class RestClientHttpInterfaceIntegrationConfigurationTests { + @Test + fun getAuthenticatedUser( + @Autowired webServer: MockWebServer, + @Autowired authorizedClients: OAuth2AuthorizedClientManager, + @Autowired users: UserService + ) { + val registration = CommonOAuth2Provider.GITHUB.getBuilder("github").clientId("github").build() + + val issuedAt = Instant.now() + val expiresAt = issuedAt.plus(Duration.ofMinutes(5)) + val token = OAuth2AccessToken( + OAuth2AccessToken.TokenType.BEARER, "1234", + issuedAt, expiresAt + ) + val result = OAuth2AuthorizedClient(registration, "rob", token) + mockkObject(authorizedClients) + every { + authorizedClients.authorize(any()) + } returns result + + webServer.enqueue( + MockResponse().addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody( + """ + {"login": "rob_winch", "id": 1234, "name": "Rob Winch" } + """.trimIndent() + ) + ) + + users.getAuthenticatedUser() + + Assertions.assertThat(webServer.takeRequest().getHeader(HttpHeaders.AUTHORIZATION)) + .isEqualTo("Bearer " + token.getTokenValue()) + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.kt new file mode 100644 index 0000000000..9a5ed50ff9 --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerRestClientHttpInterfaceIntegrationConfigurationTests.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.features.integrations.rest.configurationwebclient + +import io.mockk.every +import io.mockk.mockkObject +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider +import org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid.UserService +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager +import org.springframework.security.oauth2.core.OAuth2AccessToken +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension +import reactor.core.publisher.Mono +import java.time.Duration +import java.time.Instant + +@ExtendWith(SpringExtension::class) +@ContextConfiguration(classes = [ServerWebClientHttpInterfaceIntegrationConfiguration::class]) +internal class ServerRestClientHttpInterfaceIntegrationConfigurationTests { + @Test + @Throws(InterruptedException::class) + fun getAuthenticatedUser( + @Autowired webServer: MockWebServer, + @Autowired authorizedClients: ReactiveOAuth2AuthorizedClientManager, + @Autowired users: UserService + ) { + val registration = CommonOAuth2Provider.GITHUB.getBuilder("github").clientId("github").build() + + val issuedAt = Instant.now() + val expiresAt = issuedAt.plus(Duration.ofMinutes(5)) + val token = OAuth2AccessToken( + OAuth2AccessToken.TokenType.BEARER, "1234", + issuedAt, expiresAt + ) + val result = OAuth2AuthorizedClient(registration, "rob", token) + mockkObject(authorizedClients) + every { + authorizedClients.authorize(any()) + } returns Mono.just(result) + + webServer.enqueue( + MockResponse().addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).setBody( + """ + {"login": "rob_winch", "id": 1234, "name": "Rob Winch" } + + """.trimIndent() + ) + ) + + users.getAuthenticatedUser() + + Assertions.assertThat(webServer.takeRequest().getHeader(HttpHeaders.AUTHORIZATION)) + .isEqualTo("Bearer " + token.getTokenValue()) + } +} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt new file mode 100644 index 0000000000..89fa67348e --- /dev/null +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain clients copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.kt.docs.features.integrations.rest.configurationwebclient + +import okhttp3.mockwebserver.MockWebServer +import org.mockito.Mockito +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.kt.docs.features.integrations.rest.clientregistrationid.UserService +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.web.client.support.OAuth2RestClientHttpServiceGroupConfigurer +import org.springframework.security.oauth2.client.web.reactive.function.client.support.OAuth2WebClientHttpServiceGroupConfigurer +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer +import org.springframework.web.service.registry.HttpServiceGroup +import org.springframework.web.service.registry.HttpServiceGroupConfigurer +import org.springframework.web.service.registry.HttpServiceGroupConfigurer.ClientCallback +import org.springframework.web.service.registry.ImportHttpServices + +/** + * Documentation for [OAuth2RestClientHttpServiceGroupConfigurer]. + * @author Rob Winch + */ +@Configuration(proxyBeanMethods = false) +@ImportHttpServices(types = [UserService::class], clientType = HttpServiceGroup.ClientType.WEB_CLIENT) +class ServerWebClientHttpInterfaceIntegrationConfiguration { + // tag::config[] + @Bean + fun securityConfigurer( + manager: ReactiveOAuth2AuthorizedClientManager? + ): OAuth2WebClientHttpServiceGroupConfigurer { + return OAuth2WebClientHttpServiceGroupConfigurer.from(manager) + } + + // end::config[] + @Bean + fun authorizedClientManager(): ReactiveOAuth2AuthorizedClientManager? { + return Mockito.mock(ReactiveOAuth2AuthorizedClientManager::class.java) + } + + @Bean + fun groupConfigurer(server: MockWebServer): WebClientHttpServiceGroupConfigurer { + return WebClientHttpServiceGroupConfigurer { groups: HttpServiceGroupConfigurer.Groups? -> + val baseUrl = server.url("").toString() + groups!! + .forEachClient(ClientCallback { group: HttpServiceGroup?, builder: WebClient.Builder? -> + builder!! + .baseUrl(baseUrl) + .defaultHeader("Accept", "application/vnd.github.v3+json") + }) + } + } + + @Bean + fun mockServer(): MockWebServer { + return MockWebServer() + } +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/annotation/ClientRegistrationId.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/annotation/ClientRegistrationId.java new file mode 100644 index 0000000000..30fac85fd3 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/annotation/ClientRegistrationId.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; + +/** + * This annotation can be added to the method of an interface based HTTP client created + * using {@link org.springframework.web.service.invoker.HttpServiceProxyFactory} to + * automatically associate an OAuth token with the request. + * + * @author Rob Winch + * @since 7.0 + * @see org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor + */ +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface ClientRegistrationId { + + /** + * Sets the client registration identifier. + * @return the client registration identifier + */ + @AliasFor("value") + String registrationId() default ""; + + /** + * The default attribute for this annotation. This is an alias for + * {@link #registrationId()}. For example, + * {@code @RegisteredOAuth2AuthorizedClient("login-client")} is equivalent to + * {@code @RegisteredOAuth2AuthorizedClient(registrationId="login-client")}. + * @return the client registration identifier + */ + @AliasFor("registrationId") + String value() default ""; + +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ClientAttributes.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ClientAttributes.java new file mode 100644 index 0000000000..6075ca6626 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ClientAttributes.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web; + +import java.util.Map; +import java.util.function.Consumer; + +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.util.Assert; + +/** + * Used for accessing the attribute that stores the the + * {@link ClientRegistration#getRegistrationId()}. This ensures that + * {@link org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor} + * aligns with all of ways of setting on both + * {@link org.springframework.web.client.RestClient} and + * {@link org.springframework.web.reactive.function.client.WebClient}. + * + * @see org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor + * @see org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver + * @see org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction + * @see org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction + */ +public final class ClientAttributes { + + private static final String CLIENT_REGISTRATION_ID_ATTR_NAME = ClientRegistration.class.getName() + .concat(".CLIENT_REGISTRATION_ID"); + + /** + * Resolves the {@link ClientRegistration#getRegistrationId() clientRegistrationId} to + * be used to look up the {@link OAuth2AuthorizedClient}. + * @param attributes the to search + * @return the registration id to use. + */ + public static String resolveClientRegistrationId(Map attributes) { + return (String) attributes.get(CLIENT_REGISTRATION_ID_ATTR_NAME); + } + + /** + * Produces a Consumer that adds the {@link ClientRegistration#getRegistrationId() + * clientRegistrationId} to be used to look up the {@link OAuth2AuthorizedClient}. + * @param clientRegistrationId the {@link ClientRegistration#getRegistrationId() + * clientRegistrationId} to be used to look up the {@link OAuth2AuthorizedClient} + * @return the {@link Consumer} to populate the attributes + */ + public static Consumer> clientRegistrationId(String clientRegistrationId) { + Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); + return (attributes) -> attributes.put(CLIENT_REGISTRATION_ID_ATTR_NAME, clientRegistrationId); + } + + private ClientAttributes() { + } + +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessor.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessor.java new file mode 100644 index 0000000000..ec6f6bedac --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessor.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client; + +import java.lang.reflect.Method; + +import org.jspecify.annotations.Nullable; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.security.oauth2.client.annotation.ClientRegistrationId; +import org.springframework.security.oauth2.client.web.ClientAttributes; +import org.springframework.web.service.invoker.HttpRequestValues; + +/** + * Invokes {@link ClientAttributes#clientRegistrationId(String)} with the value specified + * by {@link ClientRegistrationId} on the request. + * + * @author Rob Winch + * @since 7.0 + */ +public final class ClientRegistrationIdProcessor implements HttpRequestValues.Processor { + + public static ClientRegistrationIdProcessor DEFAULT_INSTANCE = new ClientRegistrationIdProcessor(); + + @Override + public void process(Method method, @Nullable Object[] arguments, HttpRequestValues.Builder builder) { + ClientRegistrationId registeredId = AnnotationUtils.findAnnotation(method, ClientRegistrationId.class); + if (registeredId != null) { + String registrationId = registeredId.registrationId(); + builder.configureAttributes(ClientAttributes.clientRegistrationId(registrationId)); + } + } + + private ClientRegistrationIdProcessor() { + } + +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/RequestAttributeClientRegistrationIdResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/RequestAttributeClientRegistrationIdResolver.java index f1031ae9c1..88f88fefd8 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/RequestAttributeClientRegistrationIdResolver.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/RequestAttributeClientRegistrationIdResolver.java @@ -23,7 +23,7 @@ import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequest; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.util.Assert; +import org.springframework.security.oauth2.client.web.ClientAttributes; /** * A strategy for resolving a {@code clientRegistrationId} from an intercepted request @@ -36,13 +36,9 @@ import org.springframework.util.Assert; public final class RequestAttributeClientRegistrationIdResolver implements OAuth2ClientHttpRequestInterceptor.ClientRegistrationIdResolver { - private static final String CLIENT_REGISTRATION_ID_ATTR_NAME = RequestAttributeClientRegistrationIdResolver.class - .getName() - .concat(".clientRegistrationId"); - @Override public String resolve(HttpRequest request) { - return (String) request.getAttributes().get(CLIENT_REGISTRATION_ID_ATTR_NAME); + return ClientAttributes.resolveClientRegistrationId(request.getAttributes()); } /** @@ -54,8 +50,7 @@ public final class RequestAttributeClientRegistrationIdResolver * @return the {@link Consumer} to populate the attributes */ public static Consumer> clientRegistrationId(String clientRegistrationId) { - Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); - return (attributes) -> attributes.put(CLIENT_REGISTRATION_ID_ATTR_NAME, clientRegistrationId); + return ClientAttributes.clientRegistrationId(clientRegistrationId); } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurer.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurer.java new file mode 100644 index 0000000000..115c11ed72 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client.support; + +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor; +import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor; +import org.springframework.web.client.RestClient; +import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer; +import org.springframework.web.service.invoker.HttpRequestValues; + +/** + * Simplify adding OAuth2 support to interface based rest clients that use + * {@link RestClient}. + * + * It will add {@link OAuth2ClientHttpRequestInterceptor} to the {@link RestClient} and + * {@link ClientRegistrationIdProcessor} to the + * {@link org.springframework.web.service.invoker.HttpServiceProxyFactory}. + * + * @author Rob Winch + * @since 7.0 + */ +public final class OAuth2RestClientHttpServiceGroupConfigurer implements RestClientHttpServiceGroupConfigurer { + + private final HttpRequestValues.Processor processor = ClientRegistrationIdProcessor.DEFAULT_INSTANCE; + + private final ClientHttpRequestInterceptor interceptor; + + private OAuth2RestClientHttpServiceGroupConfigurer(ClientHttpRequestInterceptor interceptor) { + this.interceptor = interceptor; + } + + @Override + public void configureGroups(Groups groups) { + // @formatter:off + groups.forEachClient((group, client) -> + client.requestInterceptor(this.interceptor) + ); + groups.forEachProxyFactory((group, factory) -> + factory.httpRequestValuesProcessor(this.processor) + ); + // @formatter:on + } + + public static OAuth2RestClientHttpServiceGroupConfigurer from( + OAuth2AuthorizedClientManager authorizedClientManager) { + OAuth2ClientHttpRequestInterceptor interceptor = new OAuth2ClientHttpRequestInterceptor( + authorizedClientManager); + return new OAuth2RestClientHttpServiceGroupConfigurer(interceptor); + } + +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java index 2d9be5ebf4..6831a46961 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java @@ -44,6 +44,7 @@ import org.springframework.security.oauth2.client.RemoveAuthorizedClientReactive import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.ClientAttributes; import org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.core.OAuth2AuthorizationException; @@ -104,13 +105,6 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements */ private static final String OAUTH2_AUTHORIZED_CLIENT_ATTR_NAME = OAuth2AuthorizedClient.class.getName(); - /** - * The client request attribute name used to locate the - * {@link ClientRegistration#getRegistrationId()} - */ - private static final String CLIENT_REGISTRATION_ID_ATTR_NAME = OAuth2AuthorizedClient.class.getName() - .concat(".CLIENT_REGISTRATION_ID"); - /** * The request attribute name used to locate the * {@link org.springframework.web.server.ServerWebExchange}. @@ -292,7 +286,7 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements * @return the {@link Consumer} to populate the attributes */ public static Consumer> clientRegistrationId(String clientRegistrationId) { - return (attributes) -> attributes.put(CLIENT_REGISTRATION_ID_ATTR_NAME, clientRegistrationId); + return ClientAttributes.clientRegistrationId(clientRegistrationId); } private static String clientRegistrationId(ClientRequest request) { @@ -300,7 +294,7 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements if (authorizedClient != null) { return authorizedClient.getClientRegistration().getRegistrationId(); } - return (String) request.attributes().get(CLIENT_REGISTRATION_ID_ATTR_NAME); + return ClientAttributes.resolveClientRegistrationId(request.attributes()); } /** diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java index db136ba11b..98c4370e25 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java @@ -50,6 +50,7 @@ import org.springframework.security.oauth2.client.RemoveAuthorizedClientOAuth2Au import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.ClientAttributes; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.core.OAuth2AuthorizationException; @@ -136,9 +137,6 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement */ private static final String OAUTH2_AUTHORIZED_CLIENT_ATTR_NAME = OAuth2AuthorizedClient.class.getName(); - private static final String CLIENT_REGISTRATION_ID_ATTR_NAME = OAuth2AuthorizedClient.class.getName() - .concat(".CLIENT_REGISTRATION_ID"); - private static final String AUTHENTICATION_ATTR_NAME = Authentication.class.getName(); private static final String HTTP_SERVLET_REQUEST_ATTR_NAME = HttpServletRequest.class.getName(); @@ -311,7 +309,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement * @return the {@link Consumer} to populate the attributes */ public static Consumer> clientRegistrationId(String clientRegistrationId) { - return (attributes) -> attributes.put(CLIENT_REGISTRATION_ID_ATTR_NAME, clientRegistrationId); + return ClientAttributes.clientRegistrationId(clientRegistrationId); } /** @@ -536,7 +534,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement } static String getClientRegistrationId(Map attrs) { - return (String) attrs.get(CLIENT_REGISTRATION_ID_ATTR_NAME); + return ClientAttributes.resolveClientRegistrationId(attrs); } static Authentication getAuthentication(Map attrs) { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurer.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurer.java new file mode 100644 index 0000000000..78bf566fa3 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurer.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.reactive.function.client.support; + +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer; +import org.springframework.web.service.invoker.HttpRequestValues; + +/** + * Simplify adding OAuth2 support to interface based rest clients that use + * {@link WebClient}. + * + * @author Rob Winch + * @since 7.0 + */ +public final class OAuth2WebClientHttpServiceGroupConfigurer implements WebClientHttpServiceGroupConfigurer { + + private final HttpRequestValues.Processor processor = ClientRegistrationIdProcessor.DEFAULT_INSTANCE; + + private final ExchangeFilterFunction filter; + + private OAuth2WebClientHttpServiceGroupConfigurer(ExchangeFilterFunction filter) { + this.filter = filter; + } + + @Override + public void configureGroups(Groups groups) { + // @formatter:off + groups.forEachClient((group, client) -> + client.filter(this.filter) + ); + groups.forEachProxyFactory((group, factory) -> + factory.httpRequestValuesProcessor(this.processor) + ); + // @formatter:on + } + + /** + * Create an instance for Reactive web applications from the provided + * {@link ReactiveOAuth2AuthorizedClientManager}. + * + * It will add {@link ServerOAuth2AuthorizedClientExchangeFilterFunction} to the + * {@link WebClient} and {@link ClientRegistrationIdProcessor} to the + * {@link org.springframework.web.service.invoker.HttpServiceProxyFactory}. + * @param authorizedClientManager the manager to use. + * @return the {@link OAuth2WebClientHttpServiceGroupConfigurer}. + */ + public static OAuth2WebClientHttpServiceGroupConfigurer from( + ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { + ServerOAuth2AuthorizedClientExchangeFilterFunction filter = new ServerOAuth2AuthorizedClientExchangeFilterFunction( + authorizedClientManager); + return new OAuth2WebClientHttpServiceGroupConfigurer(filter); + } + + /** + * Create an instance for Servlet based environments from the provided + * {@link OAuth2AuthorizedClientManager}. + * + * It will add {@link ServletOAuth2AuthorizedClientExchangeFilterFunction} to the + * {@link WebClient} and {@link ClientRegistrationIdProcessor} to the + * {@link org.springframework.web.service.invoker.HttpServiceProxyFactory}. + * @param authorizedClientManager the manager to use. + * @return the {@link OAuth2WebClientHttpServiceGroupConfigurer}. + */ + public static OAuth2WebClientHttpServiceGroupConfigurer from( + OAuth2AuthorizedClientManager authorizedClientManager) { + ServletOAuth2AuthorizedClientExchangeFilterFunction filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction( + authorizedClientManager); + return new OAuth2WebClientHttpServiceGroupConfigurer(filter); + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/AbstractMockServerClientRegistrationIdProcessorTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/AbstractMockServerClientRegistrationIdProcessorTests.java new file mode 100644 index 0000000000..c30ea20e99 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/AbstractMockServerClientRegistrationIdProcessorTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client; + +import java.io.IOException; + +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.ClientRegistrationId; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; +import org.springframework.web.service.annotation.GetExchange; +import org.springframework.web.service.invoker.HttpExchangeAdapter; +import org.springframework.web.service.invoker.HttpServiceProxyFactory; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Base class for integration testing {@link ClientRegistrationIdProcessor} with + * {@link MockWebServer}. + * + * @author Rob Winch + * @since 7.0 + */ +abstract class AbstractMockServerClientRegistrationIdProcessorTests { + + static final String REGISTRATION_ID = "okta"; + + private final MockWebServer server = new MockWebServer(); + + private OAuth2AccessToken accessToken; + + protected String baseUrl; + + protected OAuth2AuthorizedClient authorizedClient; + + @BeforeEach + void setup() throws IOException { + this.server.start(); + HttpUrl url = this.server.url("/range/"); + this.baseUrl = url.toString(); + ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration() + .registrationId(REGISTRATION_ID) + .build(); + this.accessToken = TestOAuth2AccessTokens.scopes("read", "write"); + this.authorizedClient = new OAuth2AuthorizedClient(clientRegistration, "user", this.accessToken); + } + + @AfterEach + void cleanup() throws IOException { + if (this.server != null) { + this.server.shutdown(); + } + } + + void testWithAdapter(HttpExchangeAdapter adapter) throws InterruptedException { + ClientRegistrationIdProcessor processor = ClientRegistrationIdProcessor.DEFAULT_INSTANCE; + HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder() + .exchangeAdapter(adapter) + .httpRequestValuesProcessor(processor) + .build(); + MessageClient messages = factory.createClient(MessageClient.class); + + this.server.enqueue(new MockResponse().setBody("Hello OAuth2!").setResponseCode(200)); + assertThat(messages.getMessage()).isEqualTo("Hello OAuth2!"); + + String authorizationHeader = this.server.takeRequest().getHeader(HttpHeaders.AUTHORIZATION); + assertOAuthTokenValue(authorizationHeader, this.accessToken); + + } + + private static void assertOAuthTokenValue(String value, OAuth2AccessToken accessToken) { + String tokenType = accessToken.getTokenType().getValue(); + String tokenValue = accessToken.getTokenValue(); + assertThat(value).isEqualTo("%s %s".formatted(tokenType, tokenValue)); + } + + interface MessageClient { + + @GetExchange("/message") + @ClientRegistrationId(REGISTRATION_ID) + String getMessage(); + + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorRestClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorRestClientTests.java new file mode 100644 index 0000000000..a096327bae --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorRestClientTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.web.client.RestClient; +import org.springframework.web.client.support.RestClientAdapter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +/** + * Runs tests of {@link ClientRegistrationIdProcessor} with {@link RestClient} to ensure + * that all the parts work together properly. + * + * @author Rob Winch + * @since 7.0 + */ +@ExtendWith(MockitoExtension.class) +class ClientRegistrationIdProcessorRestClientTests extends AbstractMockServerClientRegistrationIdProcessorTests { + + @Mock + private OAuth2AuthorizedClientManager authorizedClientManager; + + @Test + void clientRegistrationIdProcessorWorksWithRestClientAdapter() throws InterruptedException { + OAuth2ClientHttpRequestInterceptor interceptor = new OAuth2ClientHttpRequestInterceptor( + this.authorizedClientManager); + RestClient.Builder builder = RestClient.builder().requestInterceptor(interceptor).baseUrl(this.baseUrl); + + ArgumentCaptor authorizeRequest = ArgumentCaptor.forClass(OAuth2AuthorizeRequest.class); + given(this.authorizedClientManager.authorize(authorizeRequest.capture())).willReturn(authorizedClient); + + testWithAdapter(RestClientAdapter.create(builder.build())); + + assertThat(authorizeRequest.getValue().getClientRegistrationId()).isEqualTo(REGISTRATION_ID); + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorTests.java new file mode 100644 index 0000000000..19ea292665 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; + +import org.junit.jupiter.api.Test; + +import org.springframework.security.oauth2.client.annotation.ClientRegistrationId; +import org.springframework.security.oauth2.client.web.ClientAttributes; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.service.invoker.HttpRequestValues; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link ClientRegistrationIdProcessor}. + * + * @author Rob Winch + * @since 7.0 + * @see ClientRegistrationIdProcessorWebClientTests + * @see ClientRegistrationIdProcessorRestClientTests + */ +class ClientRegistrationIdProcessorTests { + + ClientRegistrationIdProcessor processor = ClientRegistrationIdProcessor.DEFAULT_INSTANCE; + + @Test + void processWhenClientRegistrationIdPresentThenSet() { + HttpRequestValues.Builder builder = HttpRequestValues.builder(); + Method hasClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "hasClientRegistrationId"); + this.processor.process(hasClientRegistrationId, null, builder); + + String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes()); + assertThat(registrationId).isEqualTo(RestService.REGISTRATION_ID); + } + + @Test + void processWhenMetaClientRegistrationIdPresentThenSet() { + HttpRequestValues.Builder builder = HttpRequestValues.builder(); + Method hasClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "hasMetaClientRegistrationId"); + this.processor.process(hasClientRegistrationId, null, builder); + + String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes()); + assertThat(registrationId).isEqualTo(RestService.REGISTRATION_ID); + } + + @Test + void processWhenNoClientRegistrationIdPresentThenNull() { + HttpRequestValues.Builder builder = HttpRequestValues.builder(); + Method hasClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "noClientRegistrationId"); + this.processor.process(hasClientRegistrationId, null, builder); + + String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes()); + assertThat(registrationId).isNull(); + } + + interface RestService { + + String REGISTRATION_ID = "registrationId"; + + @ClientRegistrationId(REGISTRATION_ID) + void hasClientRegistrationId(); + + @MetaClientRegistrationId + void hasMetaClientRegistrationId(); + + void noClientRegistrationId(); + + } + + @Retention(RetentionPolicy.RUNTIME) + @ClientRegistrationId(RestService.REGISTRATION_ID) + @interface MetaClientRegistrationId { + + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorWebClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorWebClientTests.java new file mode 100644 index 0000000000..459264c92f --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorWebClientTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; + +import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.support.WebClientAdapter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Runs tests for {@link ClientRegistrationIdProcessor} with {@link WebClient} to ensure + * that all the parts work together properly. + * + * @author Rob Winch + * @since 7.0 + */ +@ExtendWith(MockitoExtension.class) +class ClientRegistrationIdProcessorWebClientTests extends AbstractMockServerClientRegistrationIdProcessorTests { + + @Test + void clientRegistrationIdProcessorWorksWithReactiveWebClient() throws InterruptedException { + ReactiveOAuth2AuthorizedClientManager authorizedClientManager = mock( + ReactiveOAuth2AuthorizedClientManager.class); + ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction( + authorizedClientManager); + + WebClient.Builder builder = WebClient.builder().filter(oauth2Client).baseUrl(this.baseUrl); + + ArgumentCaptor authorizeRequest = ArgumentCaptor.forClass(OAuth2AuthorizeRequest.class); + given(authorizedClientManager.authorize(authorizeRequest.capture())) + .willReturn(Mono.just(this.authorizedClient)); + + testWithAdapter(WebClientAdapter.create(builder.build())); + + assertThat(authorizeRequest.getValue().getClientRegistrationId()).isEqualTo(REGISTRATION_ID); + } + + @Test + void clientRegistrationIdProcessorWorksWithServletWebClient() throws InterruptedException { + OAuth2AuthorizedClientManager authorizedClientManager = mock(OAuth2AuthorizedClientManager.class); + + ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction( + authorizedClientManager); + + WebClient.Builder builder = WebClient.builder().filter(oauth2Client).baseUrl(this.baseUrl); + + ArgumentCaptor authorizeRequest = ArgumentCaptor.forClass(OAuth2AuthorizeRequest.class); + given(authorizedClientManager.authorize(authorizeRequest.capture())).willReturn(this.authorizedClient); + + testWithAdapter(WebClientAdapter.create(builder.build())); + + assertThat(authorizeRequest.getValue().getClientRegistrationId()).isEqualTo(REGISTRATION_ID); + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurerTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurerTests.java new file mode 100644 index 0000000000..489b4a042d --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/support/OAuth2RestClientHttpServiceGroupConfigurerTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.client.support; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor; +import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor; +import org.springframework.web.client.RestClient; +import org.springframework.web.service.invoker.HttpServiceProxyFactory; +import org.springframework.web.service.registry.HttpServiceGroupConfigurer; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +/** + * Tests {@link OAuth2RestClientHttpServiceGroupConfigurer}. + * + * @author Rob Winch + */ +@ExtendWith(MockitoExtension.class) +class OAuth2RestClientHttpServiceGroupConfigurerTests { + + @Mock + private OAuth2AuthorizedClientManager authoriedClientManager; + + @Mock + private HttpServiceGroupConfigurer.Groups groups; + + @Captor + ArgumentCaptor forProxyFactory; + + @Mock + private HttpServiceProxyFactory.Builder factoryBuilder; + + @Captor + private ArgumentCaptor> configureClient; + + @Mock + private RestClient.Builder clientBuilder; + + @Test + void configureGroupsConfigureProxyFactory() { + + OAuth2RestClientHttpServiceGroupConfigurer configurer = OAuth2RestClientHttpServiceGroupConfigurer + .from(this.authoriedClientManager); + + configurer.configureGroups(this.groups); + verify(this.groups).forEachProxyFactory(this.forProxyFactory.capture()); + + this.forProxyFactory.getValue().withProxyFactory(null, this.factoryBuilder); + + verify(this.factoryBuilder).httpRequestValuesProcessor(ClientRegistrationIdProcessor.DEFAULT_INSTANCE); + } + + @Test + void configureGroupsConfigureClient() { + OAuth2RestClientHttpServiceGroupConfigurer configurer = OAuth2RestClientHttpServiceGroupConfigurer + .from(this.authoriedClientManager); + + configurer.configureGroups(this.groups); + verify(this.groups).forEachClient(this.configureClient.capture()); + + this.configureClient.getValue().withClient(null, this.clientBuilder); + + verify(this.clientBuilder).requestInterceptor(any(OAuth2ClientHttpRequestInterceptor.class)); + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurerTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurerTests.java new file mode 100644 index 0000000000..058d434386 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/support/OAuth2WebClientHttpServiceGroupConfigurerTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.client.web.reactive.function.client.support; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.client.ClientRegistrationIdProcessor; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.service.invoker.HttpServiceProxyFactory; +import org.springframework.web.service.registry.HttpServiceGroupConfigurer; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +/** + * Tests {@link OAuth2WebClientHttpServiceGroupConfigurer}. + * + * @author Rob Winch + */ +@ExtendWith(MockitoExtension.class) +class OAuth2WebClientHttpServiceGroupConfigurerTests { + + @Mock + private OAuth2AuthorizedClientManager authoriedClientManager; + + @Mock + private HttpServiceGroupConfigurer.Groups groups; + + @Captor + ArgumentCaptor forProxyFactory; + + @Mock + private HttpServiceProxyFactory.Builder factoryBuilder; + + @Captor + private ArgumentCaptor> configureClient; + + @Mock + private WebClient.Builder clientBuilder; + + @Test + void configureGroupsConfigureProxyFactory() { + + OAuth2WebClientHttpServiceGroupConfigurer configurer = OAuth2WebClientHttpServiceGroupConfigurer + .from(this.authoriedClientManager); + + configurer.configureGroups(this.groups); + verify(this.groups).forEachProxyFactory(this.forProxyFactory.capture()); + + this.forProxyFactory.getValue().withProxyFactory(null, this.factoryBuilder); + + verify(this.factoryBuilder).httpRequestValuesProcessor(ClientRegistrationIdProcessor.DEFAULT_INSTANCE); + } + + @Test + void configureGroupsConfigureClient() { + OAuth2WebClientHttpServiceGroupConfigurer configurer = OAuth2WebClientHttpServiceGroupConfigurer + .from(this.authoriedClientManager); + + configurer.configureGroups(this.groups); + verify(this.groups).forEachClient(this.configureClient.capture()); + + this.configureClient.getValue().withClient(null, this.clientBuilder); + + verify(this.clientBuilder).filter(any(ExchangeFilterFunction.class)); + } + +} From c2c84c42435ec7dda4ee242ee21689235957a4e4 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 2 Jun 2025 16:19:01 +0700 Subject: [PATCH 375/504] Update HttpSecurity javadoc Signed-off-by: Tran Ngoc Nhan --- .../config/annotation/web/builders/HttpSecurity.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 0727ba33bd..ed84d98016 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -107,7 +107,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; * A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the * namespace configuration. It allows configuring web based security for specific http * requests. By default it will be applied to all requests, but can be restricted using - * {@link #requestMatcher(RequestMatcher)} or other similar methods. + * {@link #authorizeHttpRequests(Customizer)} or other similar methods. * *

Example Usage

* @@ -124,7 +124,12 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; * * @Bean * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - * http.authorizeHttpRequests().requestMatchers("/**").hasRole("USER").and().formLogin(); + * http + * .authorizeHttpRequests((authorizeHttpRequests) -> + * authorizeHttpRequests + * .requestMatchers("/**").hasRole("USER") + * ) + * .formLogin(withDefaults()); * return http.build(); * } * From 9cf563891419f09d93c9cfb12155a7785e5673e8 Mon Sep 17 00:00:00 2001 From: chanbinme Date: Sun, 15 Jun 2025 23:50:38 +0900 Subject: [PATCH 376/504] Add null check for authentication token in JwtAuthenticationProvider Add Assert.notNull validation to ensure the authentication token returned by jwtAuthenticationConverter is not null, preventing potential NullPointerException in subsequent operations. Signed-off-by: chanbinme --- .../JwtAuthenticationProvider.java | 1 + .../JwtAuthenticationProviderTests.java | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.java index cdca4ffc0c..95d7574eb4 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProvider.java @@ -87,6 +87,7 @@ public final class JwtAuthenticationProvider implements AuthenticationProvider { BearerTokenAuthenticationToken bearer = (BearerTokenAuthenticationToken) authentication; Jwt jwt = getJwt(bearer); AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt); + Assert.notNull(token, "token cannot be null"); if (token.getDetails() == null) { token.setDetails(bearer.getDetails()); } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java index b4438ba28f..6c5912df10 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java @@ -35,8 +35,7 @@ import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.*; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -152,6 +151,19 @@ public class JwtAuthenticationProviderTests { // @formatter:on } + @Test + public void authenticateWhenConverterReturnsNullThenThrowException() { + BearerTokenAuthenticationToken token = this.authentication(); + Jwt jwt = TestJwts.jwt().build(); + given(this.jwtDecoder.decode("token")).willReturn(jwt); + given(this.jwtAuthenticationConverter.convert(jwt)).willReturn(null); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.provider.authenticate(token)) + .withMessageContaining("token cannot be null"); + // @formatter:on + } + @Test public void supportsWhenBearerTokenAuthenticationTokenThenReturnsTrue() { assertThat(this.provider.supports(BearerTokenAuthenticationToken.class)).isTrue(); From 18010f9914e3ab938b51f459c83451e3721fedf2 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:20:22 -0500 Subject: [PATCH 377/504] Fix JwtAuthenticationProvider Checkstyle Issue gh-17251 --- .../authentication/JwtAuthenticationProviderTests.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java index 6c5912df10..c202dab8cd 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtAuthenticationProviderTests.java @@ -35,7 +35,9 @@ import org.springframework.security.oauth2.jwt.JwtException; import org.springframework.security.oauth2.jwt.TestJwts; import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; From 709f5db0e5d0b86806c45f9a54c9e57ffdb19b97 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Mon, 2 Jun 2025 16:18:25 +0700 Subject: [PATCH 378/504] Polish Webauthn4JRelyingPartyOperations Signed-off-by: Tran Ngoc Nhan --- .../management/Webauthn4JRelyingPartyOperations.java | 5 +---- .../management/Webauthn4jRelyingPartyOperationsTests.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java b/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java index 59d0729288..74ea3fa5f6 100644 --- a/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java +++ b/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java @@ -199,7 +199,7 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe } private static List credentialDescriptors(List credentialRecords) { - List result = new ArrayList(); + List result = new ArrayList<>(); for (CredentialRecord credentialRecord : credentialRecords) { Bytes id = Bytes.fromBase64(credentialRecord.getCredentialId().toBase64UrlString()); PublicKeyCredentialDescriptor credentialDescriptor = PublicKeyCredentialDescriptor.builder() @@ -372,9 +372,6 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe Authenticator authenticator = new AuthenticatorImpl(data, attestationObject.getAttestationStatement(), credentialRecord.getSignatureCount()); - if (authenticator == null) { - throw new IllegalStateException("No authenticator found"); - } Set origins = toOrigins(); Challenge challenge = new DefaultChallenge(requestOptions.getChallenge().getBytes()); // FIXME: should populate this diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java index 57c551c215..5b4ca74145 100644 --- a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java +++ b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java @@ -138,7 +138,7 @@ class Webauthn4jRelyingPartyOperationsTests { @Test void createPublicKeyCredentialCreationOptionsWhenAnonymousThenIllegalArgumentException() { AnonymousAuthenticationToken anonymous = new AnonymousAuthenticationToken("key", "notAuthenticated", - Set.of(() -> "ROLE_ANOYMOUS")); + Set.of(() -> "ROLE_ANONYMOUS")); assertThatIllegalArgumentException() .isThrownBy(() -> this.rpOperations.createPublicKeyCredentialCreationOptions( new ImmutablePublicKeyCredentialCreationOptionsRequest(anonymous))); From ee09215f89d5e8edc4de8ce0de5ae14525aa6c52 Mon Sep 17 00:00:00 2001 From: Suraj Bhadrike Date: Fri, 9 May 2025 01:43:55 +0530 Subject: [PATCH 379/504] Add NimbusJwtEncoder Builders Closes gh-16267 Signed-off-by: Suraj Bhadrike --- .../security/oauth2/jwt/NimbusJwtEncoder.java | 267 +++++++++++++++++- .../oauth2/jwt/NimbusJwtEncoderTests.java | 190 +++++++++++++ 2 files changed, 454 insertions(+), 3 deletions(-) diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java index fb0468fa9b..8e1b7f57e6 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java @@ -18,6 +18,8 @@ package org.springframework.security.oauth2.jwt; import java.net.URI; import java.net.URL; +import java.security.KeyPair; +import java.security.interfaces.ECPublicKey; import java.time.Instant; import java.util.ArrayList; import java.util.Date; @@ -25,19 +27,28 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import javax.crypto.SecretKey; + import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSSigner; import com.nimbusds.jose.crypto.factories.DefaultJWSSignerFactory; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKMatcher; import com.nimbusds.jose.jwk.JWKSelector; +import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.KeyType; import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.source.ImmutableJWKSet; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jose.produce.JWSSignerFactory; @@ -47,6 +58,7 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.springframework.core.convert.converter.Converter; +import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -83,6 +95,8 @@ public final class NimbusJwtEncoder implements JwtEncoder { private static final JWSSignerFactory JWS_SIGNER_FACTORY = new DefaultJWSSignerFactory(); + private JwsHeader jwsHeader; + private final Map jwsSigners = new ConcurrentHashMap<>(); private final JWKSource jwkSource; @@ -119,14 +133,16 @@ public final class NimbusJwtEncoder implements JwtEncoder { this.jwkSelector = jwkSelector; } + public void setJwsHeader(JwsHeader jwsHeader) { + this.jwsHeader = jwsHeader; + } + @Override public Jwt encode(JwtEncoderParameters parameters) throws JwtEncodingException { Assert.notNull(parameters, "parameters cannot be null"); JwsHeader headers = parameters.getJwsHeader(); - if (headers == null) { - headers = DEFAULT_JWS_HEADER; - } + headers = (headers != null) ? headers : (this.jwsHeader != null) ? this.jwsHeader : DEFAULT_JWS_HEADER; JwtClaimsSet claims = parameters.getClaims(); JWK jwk = selectJwk(headers); @@ -369,4 +385,249 @@ public final class NimbusJwtEncoder implements JwtEncoder { } } + /** + * Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided + * {@link SecretKey}. + * @param secretKey the {@link SecretKey} to use for signing JWTs + * @return a {@link SecretKeyJwtEncoderBuilder} for further configuration + * @since 7.0 + */ + public static SecretKeyJwtEncoderBuilder withSecretKey(SecretKey secretKey) { + Assert.notNull(secretKey, "secretKey cannot be null"); + return new SecretKeyJwtEncoderBuilder(secretKey); + } + + /** + * Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided + * {@link KeyPair}. The key pair must contain either an {@link RSAKey} or an + * {@link ECKey}. + * @param keyPair the {@link KeyPair} to use for signing JWTs + * @return a {@link KeyPairJwtEncoderBuilder} for further configuration + * @since 7.0 + */ + public static KeyPairJwtEncoderBuilder withKeyPair(KeyPair keyPair) { + Assert.isTrue(keyPair != null && keyPair.getPrivate() != null && keyPair.getPublic() != null, + "keyPair, its private key, and public key must not be null"); + Assert.isTrue( + keyPair.getPrivate() instanceof java.security.interfaces.RSAKey + || keyPair.getPrivate() instanceof java.security.interfaces.ECKey, + "keyPair must be an RSAKey or an ECKey"); + if (keyPair.getPrivate() instanceof java.security.interfaces.RSAKey) { + return new RsaKeyPairJwtEncoderBuilder(keyPair); + } + if (keyPair.getPrivate() instanceof java.security.interfaces.ECKey) { + return new EcKeyPairJwtEncoderBuilder(keyPair); + } + throw new IllegalArgumentException("keyPair must be an RSAKey or an ECKey"); + } + + /** + * A builder for creating {@link NimbusJwtEncoder} instances configured with a + * {@link SecretKey}. + * + * @since 7.0 + */ + public static final class SecretKeyJwtEncoderBuilder { + + private final SecretKey secretKey; + + private String keyId; + + private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256; + + private SecretKeyJwtEncoderBuilder(SecretKey secretKey) { + this.secretKey = secretKey; + } + + /** + * Sets the JWS algorithm to use for signing. Defaults to + * {@link JWSAlgorithm#HS256}. Must be an HMAC-based algorithm (HS256, HS384, or + * HS512). + * @param macAlgorithm the {@link MacAlgorithm} to use + * @return this builder instance for method chaining + */ + public SecretKeyJwtEncoderBuilder macAlgorithm(MacAlgorithm macAlgorithm) { + Assert.notNull(macAlgorithm, "macAlgorithm cannot be null"); + Assert.state(JWSAlgorithm.Family.HMAC_SHA.contains(this.jwsAlgorithm), + () -> "The algorithm '" + this.jwsAlgorithm + "' is not compatible with a SecretKey. " + + "Please use one of the HS256, HS384, or HS512 algorithms."); + + this.jwsAlgorithm = JWSAlgorithm.parse(macAlgorithm.getName()); + return this; + } + + /** + * Sets the key ID ({@code kid}) to be included in the JWK and potentially the JWS + * header. + * @param keyId the key identifier + * @return this builder instance for method chaining + */ + public SecretKeyJwtEncoderBuilder keyId(String keyId) { + this.keyId = keyId; + return this; + } + + /** + * Builds the {@link NimbusJwtEncoder} instance. + * @return the configured {@link NimbusJwtEncoder} + * @throws IllegalStateException if the configured JWS algorithm is not compatible + * with a {@link SecretKey}. + */ + public NimbusJwtEncoder build() { + this.jwsAlgorithm = (this.jwsAlgorithm != null) ? this.jwsAlgorithm : JWSAlgorithm.HS256; + + OctetSequenceKey.Builder builder = new OctetSequenceKey.Builder(this.secretKey).keyUse(KeyUse.SIGNATURE) + .algorithm(this.jwsAlgorithm) + .keyID(this.keyId); + + OctetSequenceKey jwk = builder.build(); + JWKSource jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); + NimbusJwtEncoder encoder = new NimbusJwtEncoder(jwkSource); + encoder.setJwsHeader(JwsHeader.with(MacAlgorithm.from(this.jwsAlgorithm.getName())).build()); + return encoder; + } + + } + + /** + * A builder for creating {@link NimbusJwtEncoder} instances configured with a + * {@link KeyPair}. + * + * @since 7.0 + */ + public abstract static class KeyPairJwtEncoderBuilder { + + private final KeyPair keyPair; + + private String keyId; + + private JWSAlgorithm jwsAlgorithm; + + private KeyPairJwtEncoderBuilder(KeyPair keyPair) { + this.keyPair = keyPair; + } + + /** + * Sets the JWS algorithm to use for signing. Must be compatible with the key type + * (RSA or EC). If not set, a default algorithm will be chosen based on the key + * type (e.g., RS256 for RSA, ES256 for EC). + * @param signatureAlgorithm the {@link SignatureAlgorithm} to use + * @return this builder instance for method chaining + */ + public KeyPairJwtEncoderBuilder signatureAlgorithm(SignatureAlgorithm signatureAlgorithm) { + Assert.notNull(signatureAlgorithm, "signatureAlgorithm cannot be null"); + this.jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName()); + return this; + } + + /** + * Sets the key ID ({@code kid}) to be included in the JWK and potentially the JWS + * header. + * @param keyId the key identifier + * @return this builder instance for method chaining + */ + public KeyPairJwtEncoderBuilder keyId(String keyId) { + this.keyId = keyId; + return this; + } + + /** + * Builds the {@link NimbusJwtEncoder} instance. + * @return the configured {@link NimbusJwtEncoder} + * @throws IllegalStateException if the key type is unsupported or the configured + * JWS algorithm is not compatible with the key type. + * @throws JwtEncodingException if the key is invalid (e.g., EC key with unknown + * curve) + */ + public NimbusJwtEncoder build() { + this.keyId = (this.keyId != null) ? this.keyId : UUID.randomUUID().toString(); + JWK jwk = buildJwk(); + JWKSource jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); + NimbusJwtEncoder encoder = new NimbusJwtEncoder(jwkSource); + JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.from(this.jwsAlgorithm.getName())) + .keyId(jwk.getKeyID()) + .build(); + encoder.setJwsHeader(jwsHeader); + return encoder; + } + + protected abstract JWK buildJwk(); + + } + + /** + * A builder for creating {@link NimbusJwtEncoder} instances configured with a + * {@link KeyPair}. + * + * @since 7.0 + */ + public static final class RsaKeyPairJwtEncoderBuilder extends KeyPairJwtEncoderBuilder { + + private RsaKeyPairJwtEncoderBuilder(KeyPair keyPair) { + super(keyPair); + } + + @Override + protected JWK buildJwk() { + if (super.jwsAlgorithm == null) { + super.jwsAlgorithm = JWSAlgorithm.RS256; + } + Assert.state(JWSAlgorithm.Family.RSA.contains(super.jwsAlgorithm), + () -> "The algorithm '" + super.jwsAlgorithm + "' is not compatible with an RSAKey. " + + "Please use one of the RS256, RS384, RS512, PS256, PS384, or PS512 algorithms."); + + RSAKey.Builder builder = new RSAKey.Builder( + (java.security.interfaces.RSAPublicKey) super.keyPair.getPublic()) + .privateKey(super.keyPair.getPrivate()) + .keyID(super.keyId) + .keyUse(KeyUse.SIGNATURE) + .algorithm(super.jwsAlgorithm); + return builder.build(); + } + + } + + /** + * A builder for creating {@link NimbusJwtEncoder} instances configured with a + * {@link KeyPair}. + * + * @since 7.0 + */ + public static final class EcKeyPairJwtEncoderBuilder extends KeyPairJwtEncoderBuilder { + + private EcKeyPairJwtEncoderBuilder(KeyPair keyPair) { + super(keyPair); + } + + @Override + protected JWK buildJwk() { + if (super.jwsAlgorithm == null) { + super.jwsAlgorithm = JWSAlgorithm.ES256; + } + Assert.state(JWSAlgorithm.Family.EC.contains(super.jwsAlgorithm), + () -> "The algorithm '" + super.jwsAlgorithm + "' is not compatible with an ECKey. " + + "Please use one of the ES256, ES384, or ES512 algorithms."); + + ECPublicKey publicKey = (ECPublicKey) super.keyPair.getPublic(); + Curve curve = Curve.forECParameterSpec(publicKey.getParams()); + if (curve == null) { + throw new JwtEncodingException("Unable to determine Curve for EC public key."); + } + + com.nimbusds.jose.jwk.ECKey.Builder builder = new com.nimbusds.jose.jwk.ECKey.Builder(curve, publicKey) + .privateKey(super.keyPair.getPrivate()) + .keyUse(KeyUse.SIGNATURE) + .keyID(super.keyId) + .algorithm(super.jwsAlgorithm); + + try { + return builder.build(); + } + catch (IllegalStateException ex) { + throw new IllegalArgumentException("Failed to build ECKey: " + ex.getMessage(), ex); + } + } + + } + } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java index ab17156eac..2abbaebf33 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java @@ -16,12 +16,20 @@ package org.springframework.security.oauth2.jwt; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.UUID; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.KeySourceException; @@ -48,6 +56,7 @@ import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willAnswer; @@ -344,6 +353,187 @@ public class NimbusJwtEncoderTests { verifyNoInteractions(selector); } + @Test + void secretKeyBuilderWithDefaultAlgorithm() { + SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); + assertThatNoException().isThrownBy(jwt::getClaims); + assertJwt(jwt); + } + + @Test + void secretKeyBuilderWithKeyId() { + SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); + String keyId = "test-key-id"; + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).keyId(keyId).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("kid").toString()).isEqualTo(keyId); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); + assertThatNoException().isThrownBy(jwt::getClaims); + assertJwt(jwt); + } + + @Test + void secretKeyBuilderWithCustomJwkSelector() { + SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); + String keyId = "test-key-id"; + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).keyId(keyId).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("kid")).isEqualTo(keyId); + assertThat(jwt.getClaims()).containsEntry("sub", "subject"); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void secretKeyBuilderWithCustomHeaders() { + SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); + JwtClaimsSet claims = buildClaims(); + JwsHeader headers = JwsHeader.with(org.springframework.security.oauth2.jose.jws.MacAlgorithm.HS256) + .type("JWT") + .contentType("application/jwt") + .build(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(headers, claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("typ").toString()).isEqualTo("JWT"); + assertThat(jwt.getHeaders().get("cty").toString()).isEqualTo("application/jwt"); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void keyPairBuilderWithRsaDefaultAlgorithm() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS256"); + assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); + assertThat(jwt.getAudience()).isEqualTo(claims.getAudience()); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void keyPairBuilderWithRsaCustomAlgorithm() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair) + .signatureAlgorithm(SignatureAlgorithm.RS512) + .build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS512"); + assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void keyPairBuilderWithEcDefaultAlgorithm() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); + keyPairGenerator.initialize(256); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("ES256"); + assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void keyPairBuilderWithEcCustomAlgorithm() throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); + keyPairGenerator.initialize(256); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair) + .keyId(UUID.randomUUID().toString()) + .signatureAlgorithm(SignatureAlgorithm.ES256) + .build(); + + JwtClaimsSet claims = buildClaims(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("ES256"); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + assertJwt(jwt); + } + + @Test + void keyPairBuilderWithKeyId() throws Exception { // d + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + String keyId = "test-key-id"; + JwtClaimsSet claims = buildClaims(); + + NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).keyId(keyId).build(); + Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); + + assertThat(jwt).isNotNull(); + assertThat(jwt.getHeaders().get("kid")).isEqualTo(keyId); + assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS256"); + assertThatNoException().isThrownBy(() -> jwt.getClaims()); + } + + private JwtClaimsSet buildClaims() { + Instant now = Instant.now(); + return JwtClaimsSet.builder() + .issuer("https://example.com") + .subject("subject") + .audience(Collections.singletonList("audience")) + .issuedAt(now) + .notBefore(now) + .expiresAt(now.plus(1, ChronoUnit.HOURS)) + .id(UUID.randomUUID().toString()) + .claim("custom", "value") + .build(); + } + + private static void assertJwt(Jwt jwt) { + assertThat(jwt.getIssuer().toString()).isEqualTo("https://example.com"); + assertThat(jwt.getSubject()).isEqualTo("subject"); + assertThat(jwt.getAudience()).containsExactly("audience"); + assertThat(jwt.getIssuedAt()).isNotNull(); + assertThat(jwt.getNotBefore()).isNotNull(); + assertThat(jwt.getExpiresAt()).isNotNull(); + assertThat(jwt.getId()).isNotNull(); + assertThat(jwt.getClaim("custom").toString()).isEqualTo("value"); + } + private static final class JwkListResultCaptor implements Answer> { private List result; From 676b44ebb052d4600bc99e6ecb3fb4f656b85a8a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:45:41 -0600 Subject: [PATCH 380/504] Polish NimbusJwtEncoder Builders - Simplify withKeyPair methods to match withPublicKey convention in NimbusJwtDecoder - Update tests to confirm support of other algorithms - Update constructor to apply additional JWK properties to the default header - Deduce the possibly algorithms for a given key based on curve and key size - Remove algorithm method from EC builder since the algorithm is determined by the Curve of the EC Key Issue gh-16267 Co-Authored-By: Suraj Bhadrike --- .../security/oauth2/jwt/JWKS.java | 87 ++++++ .../security/oauth2/jwt/NimbusJwtEncoder.java | 288 +++++++++--------- .../oauth2/jwt/NimbusJwtEncoderTests.java | 213 ++++++------- 3 files changed, 323 insertions(+), 265 deletions(-) create mode 100644 oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JWKS.java diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JWKS.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JWKS.java new file mode 100644 index 0000000000..8596749bc2 --- /dev/null +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JWKS.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.oauth2.jwt; + +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Date; +import java.util.Set; + +import javax.crypto.SecretKey; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.crypto.impl.ECDSA; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.KeyOperation; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.jwk.RSAKey; + +final class JWKS { + + private JWKS() { + + } + + static OctetSequenceKey.Builder signing(SecretKey key) throws JOSEException { + Date issued = new Date(); + return new OctetSequenceKey.Builder(key).keyOperations(Set.of(KeyOperation.SIGN)) + .keyUse(KeyUse.SIGNATURE) + .algorithm(JWSAlgorithm.HS256) + .keyIDFromThumbprint() + .issueTime(issued) + .notBeforeTime(issued); + } + + static ECKey.Builder signingWithEc(ECPublicKey pub, ECPrivateKey key) throws JOSEException { + Date issued = new Date(); + Curve curve = Curve.forECParameterSpec(pub.getParams()); + JWSAlgorithm algorithm = computeAlgorithm(curve); + return new ECKey.Builder(curve, pub).privateKey(key) + .keyOperations(Set.of(KeyOperation.SIGN)) + .keyUse(KeyUse.SIGNATURE) + .algorithm(algorithm) + .keyIDFromThumbprint() + .issueTime(issued) + .notBeforeTime(issued); + } + + private static JWSAlgorithm computeAlgorithm(Curve curve) { + try { + return ECDSA.resolveAlgorithm(curve); + } + catch (JOSEException ex) { + throw new IllegalArgumentException(ex); + } + } + + static RSAKey.Builder signingWithRsa(RSAPublicKey pub, RSAPrivateKey key) throws JOSEException { + Date issued = new Date(); + return new RSAKey.Builder(pub).privateKey(key) + .keyUse(KeyUse.SIGNATURE) + .keyOperations(Set.of(KeyOperation.SIGN)) + .algorithm(JWSAlgorithm.RS256) + .keyIDFromThumbprint() + .issueTime(issued) + .notBeforeTime(issued); + } + +} diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java index 8e1b7f57e6..8fd1ada518 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoder.java @@ -19,7 +19,10 @@ package org.springframework.security.oauth2.jwt; import java.net.URI; import java.net.URL; import java.security.KeyPair; +import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.time.Instant; import java.util.ArrayList; import java.util.Date; @@ -27,8 +30,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import javax.crypto.SecretKey; @@ -37,6 +40,7 @@ import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.MACSigner; import com.nimbusds.jose.crypto.factories.DefaultJWSSignerFactory; import com.nimbusds.jose.jwk.Curve; import com.nimbusds.jose.jwk.ECKey; @@ -58,11 +62,14 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.springframework.core.convert.converter.Converter; +import org.springframework.security.oauth2.jose.jws.JwsAlgorithm; import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import org.springframework.util.function.ThrowingBiFunction; +import org.springframework.util.function.ThrowingFunction; /** * An implementation of a {@link JwtEncoder} that encodes a JSON Web Token (JWT) using the @@ -74,6 +81,8 @@ import org.springframework.util.StringUtils; * NOTE: This implementation uses the Nimbus JOSE + JWT SDK. * * @author Joe Grandja + * @author Josh Cummings + * @author Suraj Bhadrike * @since 5.6 * @see JwtEncoder * @see com.nimbusds.jose.jwk.source.JWKSource @@ -95,7 +104,7 @@ public final class NimbusJwtEncoder implements JwtEncoder { private static final JWSSignerFactory JWS_SIGNER_FACTORY = new DefaultJWSSignerFactory(); - private JwsHeader jwsHeader; + private final JwsHeader defaultJwsHeader; private final Map jwsSigners = new ConcurrentHashMap<>(); @@ -114,10 +123,35 @@ public final class NimbusJwtEncoder implements JwtEncoder { * @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource} */ public NimbusJwtEncoder(JWKSource jwkSource) { + this.defaultJwsHeader = DEFAULT_JWS_HEADER; Assert.notNull(jwkSource, "jwkSource cannot be null"); this.jwkSource = jwkSource; } + private NimbusJwtEncoder(JWK jwk) { + Assert.notNull(jwk, "jwk cannot be null"); + this.jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); + JwsAlgorithm algorithm = SignatureAlgorithm.from(jwk.getAlgorithm().getName()); + if (algorithm == null) { + algorithm = MacAlgorithm.from(jwk.getAlgorithm().getName()); + } + Assert.notNull(algorithm, "Failed to derive supported algorithm from " + jwk.getAlgorithm()); + JwsHeader.Builder builder = JwsHeader.with(algorithm).type(jwk.getKeyType().getValue()).keyId(jwk.getKeyID()); + URI x509Url = jwk.getX509CertURL(); + if (x509Url != null) { + builder.x509Url(jwk.getX509CertURL().toASCIIString()); + } + List certs = jwk.getX509CertChain(); + if (certs != null) { + builder.x509CertificateChain(certs.stream().map(Base64::toString).toList()); + } + Base64URL thumbprint = jwk.getX509CertSHA256Thumbprint(); + if (thumbprint != null) { + builder.x509SHA256Thumbprint(thumbprint.toString()); + } + this.defaultJwsHeader = builder.build(); + } + /** * Use this strategy to reduce the list of matching JWKs when there is more than one. *

@@ -133,16 +167,15 @@ public final class NimbusJwtEncoder implements JwtEncoder { this.jwkSelector = jwkSelector; } - public void setJwsHeader(JwsHeader jwsHeader) { - this.jwsHeader = jwsHeader; - } - @Override public Jwt encode(JwtEncoderParameters parameters) throws JwtEncodingException { Assert.notNull(parameters, "parameters cannot be null"); JwsHeader headers = parameters.getJwsHeader(); - headers = (headers != null) ? headers : (this.jwsHeader != null) ? this.jwsHeader : DEFAULT_JWS_HEADER; + if (headers == null) { + headers = this.defaultJwsHeader; + } + JwtClaimsSet claims = parameters.getClaims(); JWK jwk = selectJwk(headers); @@ -387,38 +420,34 @@ public final class NimbusJwtEncoder implements JwtEncoder { /** * Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided - * {@link SecretKey}. - * @param secretKey the {@link SecretKey} to use for signing JWTs - * @return a {@link SecretKeyJwtEncoderBuilder} for further configuration + * @param publicKey the {@link RSAPublicKey} and @Param privateKey the + * {@link RSAPrivateKey} to use for signing JWTs + * @return a {@link RsaKeyPairJwtEncoderBuilder} * @since 7.0 */ - public static SecretKeyJwtEncoderBuilder withSecretKey(SecretKey secretKey) { - Assert.notNull(secretKey, "secretKey cannot be null"); - return new SecretKeyJwtEncoderBuilder(secretKey); + public static RsaKeyPairJwtEncoderBuilder withKeyPair(RSAPublicKey publicKey, RSAPrivateKey privateKey) { + return new RsaKeyPairJwtEncoderBuilder(publicKey, privateKey); } /** * Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided - * {@link KeyPair}. The key pair must contain either an {@link RSAKey} or an - * {@link ECKey}. - * @param keyPair the {@link KeyPair} to use for signing JWTs - * @return a {@link KeyPairJwtEncoderBuilder} for further configuration + * @param publicKey the {@link ECPublicKey} and @param privateKey the + * {@link ECPrivateKey} to use for signing JWTs + * @return a {@link EcKeyPairJwtEncoderBuilder} * @since 7.0 */ - public static KeyPairJwtEncoderBuilder withKeyPair(KeyPair keyPair) { - Assert.isTrue(keyPair != null && keyPair.getPrivate() != null && keyPair.getPublic() != null, - "keyPair, its private key, and public key must not be null"); - Assert.isTrue( - keyPair.getPrivate() instanceof java.security.interfaces.RSAKey - || keyPair.getPrivate() instanceof java.security.interfaces.ECKey, - "keyPair must be an RSAKey or an ECKey"); - if (keyPair.getPrivate() instanceof java.security.interfaces.RSAKey) { - return new RsaKeyPairJwtEncoderBuilder(keyPair); - } - if (keyPair.getPrivate() instanceof java.security.interfaces.ECKey) { - return new EcKeyPairJwtEncoderBuilder(keyPair); - } - throw new IllegalArgumentException("keyPair must be an RSAKey or an ECKey"); + public static EcKeyPairJwtEncoderBuilder withKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey) { + return new EcKeyPairJwtEncoderBuilder(publicKey, privateKey); + } + + /** + * Creates a builder for constructing a {@link NimbusJwtEncoder} using the provided + * @param secretKey + * @return a {@link SecretKeyJwtEncoderBuilder} for configuring the {@link JWK} + * @since 7.0 + */ + public static SecretKeyJwtEncoderBuilder withSecretKey(SecretKey secretKey) { + return new SecretKeyJwtEncoderBuilder(secretKey); } /** @@ -429,14 +458,29 @@ public final class NimbusJwtEncoder implements JwtEncoder { */ public static final class SecretKeyJwtEncoderBuilder { - private final SecretKey secretKey; + private static final ThrowingFunction defaultJwk = JWKS::signing; - private String keyId; + private final OctetSequenceKey.Builder builder; - private JWSAlgorithm jwsAlgorithm = JWSAlgorithm.HS256; + private final Set allowedAlgorithms; private SecretKeyJwtEncoderBuilder(SecretKey secretKey) { - this.secretKey = secretKey; + Assert.notNull(secretKey, "secretKey cannot be null"); + Set allowedAlgorithms = computeAllowedAlgorithms(secretKey); + Assert.notEmpty(allowedAlgorithms, + "This key is too small for any standard JWK symmetric signing algorithm"); + this.allowedAlgorithms = allowedAlgorithms; + this.builder = defaultJwk.apply(secretKey, IllegalArgumentException::new) + .algorithm(this.allowedAlgorithms.iterator().next()); + } + + private Set computeAllowedAlgorithms(SecretKey secretKey) { + try { + return new MACSigner(secretKey).supportedJWSAlgorithms(); + } + catch (JOSEException ex) { + throw new IllegalArgumentException(ex); + } } /** @@ -446,24 +490,24 @@ public final class NimbusJwtEncoder implements JwtEncoder { * @param macAlgorithm the {@link MacAlgorithm} to use * @return this builder instance for method chaining */ - public SecretKeyJwtEncoderBuilder macAlgorithm(MacAlgorithm macAlgorithm) { + public SecretKeyJwtEncoderBuilder algorithm(MacAlgorithm macAlgorithm) { Assert.notNull(macAlgorithm, "macAlgorithm cannot be null"); - Assert.state(JWSAlgorithm.Family.HMAC_SHA.contains(this.jwsAlgorithm), - () -> "The algorithm '" + this.jwsAlgorithm + "' is not compatible with a SecretKey. " - + "Please use one of the HS256, HS384, or HS512 algorithms."); - - this.jwsAlgorithm = JWSAlgorithm.parse(macAlgorithm.getName()); + JWSAlgorithm jws = JWSAlgorithm.parse(macAlgorithm.getName()); + Assert.isTrue(this.allowedAlgorithms.contains(jws), String + .format("This key can only support " + "the following algorithms: [%s]", this.allowedAlgorithms)); + this.builder.algorithm(JWSAlgorithm.parse(macAlgorithm.getName())); return this; } /** - * Sets the key ID ({@code kid}) to be included in the JWK and potentially the JWS - * header. - * @param keyId the key identifier + * Post-process the {@link JWK} using the given {@link Consumer}. For example, you + * may use this to override the default {@code kid} + * @param jwkPostProcessor the post-processor to use * @return this builder instance for method chaining */ - public SecretKeyJwtEncoderBuilder keyId(String keyId) { - this.keyId = keyId; + public SecretKeyJwtEncoderBuilder jwkPostProcessor(Consumer jwkPostProcessor) { + Assert.notNull(jwkPostProcessor, "jwkPostProcessor cannot be null"); + jwkPostProcessor.accept(this.builder); return this; } @@ -474,17 +518,7 @@ public final class NimbusJwtEncoder implements JwtEncoder { * with a {@link SecretKey}. */ public NimbusJwtEncoder build() { - this.jwsAlgorithm = (this.jwsAlgorithm != null) ? this.jwsAlgorithm : JWSAlgorithm.HS256; - - OctetSequenceKey.Builder builder = new OctetSequenceKey.Builder(this.secretKey).keyUse(KeyUse.SIGNATURE) - .algorithm(this.jwsAlgorithm) - .keyID(this.keyId); - - OctetSequenceKey jwk = builder.build(); - JWKSource jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); - NimbusJwtEncoder encoder = new NimbusJwtEncoder(jwkSource); - encoder.setJwsHeader(JwsHeader.with(MacAlgorithm.from(this.jwsAlgorithm.getName())).build()); - return encoder; + return new NimbusJwtEncoder(this.builder.build()); } } @@ -495,137 +529,93 @@ public final class NimbusJwtEncoder implements JwtEncoder { * * @since 7.0 */ - public abstract static class KeyPairJwtEncoderBuilder { + public static final class RsaKeyPairJwtEncoderBuilder { - private final KeyPair keyPair; + private static final ThrowingBiFunction defaultKid = JWKS::signingWithRsa; - private String keyId; + private final RSAKey.Builder builder; - private JWSAlgorithm jwsAlgorithm; - - private KeyPairJwtEncoderBuilder(KeyPair keyPair) { - this.keyPair = keyPair; + private RsaKeyPairJwtEncoderBuilder(RSAPublicKey publicKey, RSAPrivateKey privateKey) { + Assert.notNull(publicKey, "publicKey cannot be null"); + Assert.notNull(privateKey, "privateKey cannot be null"); + this.builder = defaultKid.apply(publicKey, privateKey); } /** - * Sets the JWS algorithm to use for signing. Must be compatible with the key type - * (RSA or EC). If not set, a default algorithm will be chosen based on the key - * type (e.g., RS256 for RSA, ES256 for EC). + * Sets the JWS algorithm to use for signing. Defaults to + * {@link SignatureAlgorithm#RS256}. Must be an RSA-based algorithm * @param signatureAlgorithm the {@link SignatureAlgorithm} to use * @return this builder instance for method chaining */ - public KeyPairJwtEncoderBuilder signatureAlgorithm(SignatureAlgorithm signatureAlgorithm) { + public RsaKeyPairJwtEncoderBuilder algorithm(SignatureAlgorithm signatureAlgorithm) { Assert.notNull(signatureAlgorithm, "signatureAlgorithm cannot be null"); - this.jwsAlgorithm = JWSAlgorithm.parse(signatureAlgorithm.getName()); + this.builder.algorithm(JWSAlgorithm.parse(signatureAlgorithm.getName())); return this; } /** - * Sets the key ID ({@code kid}) to be included in the JWK and potentially the JWS - * header. - * @param keyId the key identifier + * Add commentMore actions Post-process the {@link JWK} using the given + * {@link Consumer}. For example, you may use this to override the default + * {@code kid} + * @param jwkPostProcessor the post-processor to use * @return this builder instance for method chaining */ - public KeyPairJwtEncoderBuilder keyId(String keyId) { - this.keyId = keyId; + public RsaKeyPairJwtEncoderBuilder jwkPostProcessor(Consumer jwkPostProcessor) { + Assert.notNull(jwkPostProcessor, "jwkPostProcessor cannot be null"); + jwkPostProcessor.accept(this.builder); return this; } /** * Builds the {@link NimbusJwtEncoder} instance. * @return the configured {@link NimbusJwtEncoder} - * @throws IllegalStateException if the key type is unsupported or the configured - * JWS algorithm is not compatible with the key type. - * @throws JwtEncodingException if the key is invalid (e.g., EC key with unknown - * curve) */ public NimbusJwtEncoder build() { - this.keyId = (this.keyId != null) ? this.keyId : UUID.randomUUID().toString(); - JWK jwk = buildJwk(); - JWKSource jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); - NimbusJwtEncoder encoder = new NimbusJwtEncoder(jwkSource); - JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.from(this.jwsAlgorithm.getName())) - .keyId(jwk.getKeyID()) - .build(); - encoder.setJwsHeader(jwsHeader); - return encoder; - } - - protected abstract JWK buildJwk(); - - } - - /** - * A builder for creating {@link NimbusJwtEncoder} instances configured with a - * {@link KeyPair}. - * - * @since 7.0 - */ - public static final class RsaKeyPairJwtEncoderBuilder extends KeyPairJwtEncoderBuilder { - - private RsaKeyPairJwtEncoderBuilder(KeyPair keyPair) { - super(keyPair); - } - - @Override - protected JWK buildJwk() { - if (super.jwsAlgorithm == null) { - super.jwsAlgorithm = JWSAlgorithm.RS256; - } - Assert.state(JWSAlgorithm.Family.RSA.contains(super.jwsAlgorithm), - () -> "The algorithm '" + super.jwsAlgorithm + "' is not compatible with an RSAKey. " - + "Please use one of the RS256, RS384, RS512, PS256, PS384, or PS512 algorithms."); - - RSAKey.Builder builder = new RSAKey.Builder( - (java.security.interfaces.RSAPublicKey) super.keyPair.getPublic()) - .privateKey(super.keyPair.getPrivate()) - .keyID(super.keyId) - .keyUse(KeyUse.SIGNATURE) - .algorithm(super.jwsAlgorithm); - return builder.build(); + return new NimbusJwtEncoder(this.builder.build()); } } /** * A builder for creating {@link NimbusJwtEncoder} instances configured with a - * {@link KeyPair}. + * {@link ECPublicKey} and {@link ECPrivateKey}. + *

+ * This builder is used to create a {@link NimbusJwtEncoder} * * @since 7.0 */ - public static final class EcKeyPairJwtEncoderBuilder extends KeyPairJwtEncoderBuilder { + public static final class EcKeyPairJwtEncoderBuilder { - private EcKeyPairJwtEncoderBuilder(KeyPair keyPair) { - super(keyPair); - } + private static final ThrowingBiFunction defaultKid = JWKS::signingWithEc; - @Override - protected JWK buildJwk() { - if (super.jwsAlgorithm == null) { - super.jwsAlgorithm = JWSAlgorithm.ES256; - } - Assert.state(JWSAlgorithm.Family.EC.contains(super.jwsAlgorithm), - () -> "The algorithm '" + super.jwsAlgorithm + "' is not compatible with an ECKey. " - + "Please use one of the ES256, ES384, or ES512 algorithms."); + private final ECKey.Builder builder; - ECPublicKey publicKey = (ECPublicKey) super.keyPair.getPublic(); + private EcKeyPairJwtEncoderBuilder(ECPublicKey publicKey, ECPrivateKey privateKey) { + Assert.notNull(publicKey, "publicKey cannot be null"); + Assert.notNull(privateKey, "privateKey cannot be null"); Curve curve = Curve.forECParameterSpec(publicKey.getParams()); - if (curve == null) { - throw new JwtEncodingException("Unable to determine Curve for EC public key."); - } + Assert.notNull(curve, "Unable to determine Curve for EC public key."); + this.builder = defaultKid.apply(publicKey, privateKey); + } - com.nimbusds.jose.jwk.ECKey.Builder builder = new com.nimbusds.jose.jwk.ECKey.Builder(curve, publicKey) - .privateKey(super.keyPair.getPrivate()) - .keyUse(KeyUse.SIGNATURE) - .keyID(super.keyId) - .algorithm(super.jwsAlgorithm); + /** + * Post-process the {@link JWK} using the given {@link Consumer}. For example, you + * may use this to override the default {@code kid} + * @param jwkPostProcessor the post-processor to use + * @return this builder instance for method chaining + */ + public EcKeyPairJwtEncoderBuilder jwkPostProcessor(Consumer jwkPostProcessor) { + Assert.notNull(jwkPostProcessor, "jwkPostProcessor cannot be null"); + jwkPostProcessor.accept(this.builder); + return this; + } - try { - return builder.build(); - } - catch (IllegalStateException ex) { - throw new IllegalArgumentException("Failed to build ECKey: " + ex.getMessage(), ex); - } + /** + * Builds the {@link NimbusJwtEncoder} instance. + * @return the configured {@link NimbusJwtEncoder} + */ + public NimbusJwtEncoder build() { + return new NimbusJwtEncoder(this.builder.build()); } } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java index 2abbaebf33..840b9cdcca 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtEncoderTests.java @@ -16,8 +16,6 @@ package org.springframework.security.oauth2.jwt; -import java.security.KeyPair; -import java.security.KeyPairGenerator; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.time.Instant; @@ -27,12 +25,15 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; +import java.util.function.Consumer; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.KeySourceException; +import com.nimbusds.jose.jwk.Curve; import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSelector; @@ -40,6 +41,8 @@ import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.OctetSequenceKey; import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.ECKeyGenerator; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jose.util.Base64URL; @@ -51,12 +54,12 @@ import org.mockito.stubbing.Answer; import org.springframework.core.convert.converter.Converter; import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jose.TestKeys; +import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willAnswer; @@ -353,160 +356,138 @@ public class NimbusJwtEncoderTests { verifyNoInteractions(selector); } + // Default algorithm @Test - void secretKeyBuilderWithDefaultAlgorithm() { - SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); + void keyPairBuilderWithRsaDefaultAlgorithm() throws JOSEException { + RSAKeyGenerator generator = new RSAKeyGenerator(2048); + RSAKey key = generator.generate(); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toRSAPublicKey(), key.toRSAPrivateKey()).build(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); - assertThatNoException().isThrownBy(jwt::getClaims); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); } @Test - void secretKeyBuilderWithKeyId() { - SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); - String keyId = "test-key-id"; + void keyPairBuilderWithEcDefaultAlgorithm() throws JOSEException { + ECKeyGenerator generator = new ECKeyGenerator(Curve.P_256); + ECKey key = generator.generate(); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toECPublicKey(), key.toECPrivateKey()).build(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).keyId(keyId).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("kid").toString()).isEqualTo(keyId); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); - assertThatNoException().isThrownBy(jwt::getClaims); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); } @Test - void secretKeyBuilderWithCustomJwkSelector() { - SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); - String keyId = "test-key-id"; + void keyPairBuilderWithSecretKeyDefaultAlgorithm() { + SecretKey key = TestKeys.DEFAULT_SECRET_KEY; + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withSecretKey(key).build(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).keyId(keyId).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("kid")).isEqualTo(keyId); - assertThat(jwt.getClaims()).containsEntry("sub", "subject"); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); } + // With custom algorithm @Test - void secretKeyBuilderWithCustomHeaders() { - SecretKey secretKey = new SecretKeySpec("thisIsASecretKeyUsedForTesting12345".getBytes(), "HMAC"); - JwtClaimsSet claims = buildClaims(); - JwsHeader headers = JwsHeader.with(org.springframework.security.oauth2.jose.jws.MacAlgorithm.HS256) - .type("JWT") - .contentType("application/jwt") + void keyPairBuilderWithRsaWithAlgorithm() throws JOSEException { + RSAKeyGenerator generator = new RSAKeyGenerator(2048); + RSAKey key = generator.generate(); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toRSAPublicKey(), key.toRSAPrivateKey()) + .algorithm(SignatureAlgorithm.RS384) .build(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withSecretKey(secretKey).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(headers, claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("typ").toString()).isEqualTo("JWT"); - assertThat(jwt.getHeaders().get("cty").toString()).isEqualTo("application/jwt"); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("HS256"); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + JwtClaimsSet claims = buildClaims(); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, SignatureAlgorithm.RS384); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); } @Test - void keyPairBuilderWithRsaDefaultAlgorithm() throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(2048); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); + void keyPairBuilderWithEcWithAlgorithm() throws JOSEException { + ECKeyGenerator generator = new ECKeyGenerator(Curve.P_384); + ECKey key = generator.generate(); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toECPublicKey(), key.toECPrivateKey()).build(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS256"); - assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); - assertThat(jwt.getAudience()).isEqualTo(claims.getAudience()); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, SignatureAlgorithm.ES384); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); } @Test - void keyPairBuilderWithRsaCustomAlgorithm() throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(2048); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); + void keyPairBuilderWithSecretKeyWithAlgorithm() { + String keyStr = UUID.randomUUID().toString(); + keyStr += keyStr; + SecretKey Key = new SecretKeySpec(keyStr.getBytes(), "AES"); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withSecretKey(Key).algorithm(MacAlgorithm.HS512).build(); JwtClaimsSet claims = buildClaims(); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); + assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, MacAlgorithm.HS512); + assertThat(jwt.getHeaders()).containsKey(JoseHeaderNames.KID); + } - NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair) - .signatureAlgorithm(SignatureAlgorithm.RS512) + @Test + void keyPairBuilderWhenShortSecretThenHigherAlgorithmNotSupported() { + String keyStr = UUID.randomUUID().toString(); + SecretKey Key = new SecretKeySpec(keyStr.getBytes(), "AES"); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> NimbusJwtEncoder.withSecretKey(Key).algorithm(MacAlgorithm.HS512).build()); + } + + @Test + void keyPairBuilderWhenTooShortSecretThenException() { + SecretKey Key = new SecretKeySpec("key".getBytes(), "AES"); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> NimbusJwtEncoder.withSecretKey(Key)); + } + + // with custom jwkPostProcessor + @Test + void keyPairBuilderWithRsaWithAlgorithmAndJwkSource() throws JOSEException { + RSAKeyGenerator generator = new RSAKeyGenerator(2048); + RSAKey key = generator.generate(); + String keyId = UUID.randomUUID().toString(); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toRSAPublicKey(), key.toRSAPrivateKey()) + .algorithm(SignatureAlgorithm.RS384) + .jwkPostProcessor((builder) -> builder.keyID(keyId)) .build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS512"); - assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); - assertJwt(jwt); - } - - @Test - void keyPairBuilderWithEcDefaultAlgorithm() throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); - keyPairGenerator.initialize(256); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("ES256"); - assertThat(jwt.getSubject()).isEqualTo(claims.getSubject()); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, SignatureAlgorithm.RS384); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.KID, keyId); } @Test - void keyPairBuilderWithEcCustomAlgorithm() throws Exception { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); - keyPairGenerator.initialize(256); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); - NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair) - .keyId(UUID.randomUUID().toString()) - .signatureAlgorithm(SignatureAlgorithm.ES256) + void keyPairBuilderWithEcWithAlgorithmAndJwkSource() throws JOSEException { + ECKeyGenerator generator = new ECKeyGenerator(Curve.P_256); + ECKey key = generator.generate(); + String keyId = UUID.randomUUID().toString(); + Consumer jwkPostProcessor = (builder) -> builder.keyID(keyId); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withKeyPair(key.toECPublicKey(), key.toECPrivateKey()) + .jwkPostProcessor(jwkPostProcessor) .build(); - JwtClaimsSet claims = buildClaims(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("ES256"); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, SignatureAlgorithm.ES256); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.KID, keyId); } @Test - void keyPairBuilderWithKeyId() throws Exception { // d - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(2048); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); - String keyId = "test-key-id"; + void keyPairBuilderWithSecretKeyWithAlgorithmAndJwkSource() { + final String keyStr = UUID.randomUUID().toString(); + SecretKey key = new SecretKeySpec(keyStr.getBytes(), "HS256"); + String keyId = UUID.randomUUID().toString(); + Consumer jwkPostProcessor = (builder) -> builder.keyID(keyId); + NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withSecretKey(key).jwkPostProcessor(jwkPostProcessor).build(); JwtClaimsSet claims = buildClaims(); - - NimbusJwtEncoder encoder = NimbusJwtEncoder.withKeyPair(keyPair).keyId(keyId).build(); - Jwt jwt = encoder.encode(JwtEncoderParameters.from(claims)); - - assertThat(jwt).isNotNull(); - assertThat(jwt.getHeaders().get("kid")).isEqualTo(keyId); - assertThat(jwt.getHeaders().get("alg").toString()).isEqualTo("RS256"); - assertThatNoException().isThrownBy(() -> jwt.getClaims()); + Jwt jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)); + assertJwt(jwt); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.ALG, MacAlgorithm.HS256); + assertThat(jwt.getHeaders()).containsEntry(JoseHeaderNames.KID, keyId); } private JwtClaimsSet buildClaims() { From 06ed6ef342a114e8710b629c9123d857a00b4890 Mon Sep 17 00:00:00 2001 From: evga7 Date: Sun, 15 Jun 2025 05:04:38 +0900 Subject: [PATCH 381/504] Simplify Csrf Processor Decision Logic Replaces repeated if-else string comparisons with a Set.contains() check for known WebSocket handshake handler class names in MessageSecurityPostProcessor. Improves readability and maintainability without changing behavior. Signed-off-by: Wonpyo Hong --- ...ageBrokerSecurityBeanDefinitionParser.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java index edb6646b36..9f4dc88f15 100644 --- a/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java @@ -19,6 +19,11 @@ package org.springframework.security.config.websocket; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; +import java.util.Collections; + import java.util.function.Supplier; import org.w3c.dom.Element; @@ -307,6 +312,13 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements private static final String TEMPLATE_EXPRESSION_BEAN_ID = "annotationExpressionTemplateDefaults"; + private static final Set CSRF_HANDSHAKE_HANDLER_CLASSES = Collections.unmodifiableSet( + new HashSet<>(Arrays.asList( + "org.springframework.web.socket.server.support.WebSocketHttpRequestHandler", + "org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService", + "org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService" + ))); + private final String inboundSecurityInterceptorId; private final boolean sameOriginDisabled; @@ -345,16 +357,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements } } } - else if ("org.springframework.web.socket.server.support.WebSocketHttpRequestHandler" - .equals(beanClassName)) { - addCsrfTokenHandshakeInterceptor(bd); - } - else if ("org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService" - .equals(beanClassName)) { - addCsrfTokenHandshakeInterceptor(bd); - } - else if ("org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService" - .equals(beanClassName)) { + else if (CSRF_HANDSHAKE_HANDLER_CLASSES.contains(beanClassName)) { addCsrfTokenHandshakeInterceptor(bd); } } From 42e24aa53c3ca587c1a398183e7762cae5df66c0 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Tue, 17 Jun 2025 16:39:05 -0600 Subject: [PATCH 382/504] Fix Formatting --- ...etMessageBrokerSecurityBeanDefinitionParser.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java index 9f4dc88f15..2c903ce527 100644 --- a/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/websocket/WebSocketMessageBrokerSecurityBeanDefinitionParser.java @@ -16,14 +16,13 @@ package org.springframework.security.config.websocket; +import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; -import java.util.Collections; - import java.util.function.Supplier; import org.w3c.dom.Element; @@ -313,11 +312,9 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements private static final String TEMPLATE_EXPRESSION_BEAN_ID = "annotationExpressionTemplateDefaults"; private static final Set CSRF_HANDSHAKE_HANDLER_CLASSES = Collections.unmodifiableSet( - new HashSet<>(Arrays.asList( - "org.springframework.web.socket.server.support.WebSocketHttpRequestHandler", + new HashSet<>(Arrays.asList("org.springframework.web.socket.server.support.WebSocketHttpRequestHandler", "org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService", - "org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService" - ))); + "org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService"))); private final String inboundSecurityInterceptorId; From a66abaa2928310810734fe74677d1e385f1c3bf1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:50:29 +0000 Subject: [PATCH 383/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 5010f0f000939088be7c89e8756e9444ce75aff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:50:36 +0000 Subject: [PATCH 384/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 7334e1216720ad42db0608735797d3bae0e33fc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:51:08 +0000 Subject: [PATCH 385/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a716c7468a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 8e217686dcc55b3f19bfaaa173e91af0141c1278 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:51:16 +0000 Subject: [PATCH 386/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 4322bf555090201875e5514b9223a9532f42d749 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:51:17 +0000 Subject: [PATCH 387/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..98c4e279d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 0af0c15cd689d53c2c8a4b7154c7dc607c1c69a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:51:21 +0000 Subject: [PATCH 388/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From ae7d1fbc2f26243d40c38115ced09cb4903de8c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:51:29 +0000 Subject: [PATCH 389/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..0475e149f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 527f276eb6b3e894cca69a8638a9954351bcffc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:52:09 +0000 Subject: [PATCH 390/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 22614d45219cb253c125440e013f80502004399b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:54:17 +0000 Subject: [PATCH 391/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 7300be31617ab97875b31304fb541453267f6127 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:54:49 +0000 Subject: [PATCH 392/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 275893f1d173cdfffc1f91ecc94e605f9c75deb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 03:54:59 +0000 Subject: [PATCH 393/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From e17c256fceda2a7edfd8dbc3a553f6b2cca94abf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 04:00:21 +0000 Subject: [PATCH 394/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..ddf324f57b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 349451c8a525a989730abdcf9bd8ee65e0a85b88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 04:01:03 +0000 Subject: [PATCH 395/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..f8ffc67025 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 6ddb964c619ed1c9eeead3f6b2c86718ee320434 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 18 Jun 2025 18:29:16 -0600 Subject: [PATCH 396/504] Remove ApacheDS Support Closes gh-13852 --- config/spring-security-config.gradle | 6 - ...onProviderBuilderSecurityBuilderTests.java | 10 +- ...indAuthenticationManagerFactoryITests.java | 12 +- ...sonAuthenticationManagerFactoryITests.java | 12 +- ...LdapProviderBeanDefinitionParserTests.java | 23 +- .../LdapServerBeanDefinitionParserTests.java | 6 +- .../resources/logback-test.xml | 1 - .../security/config/BeanIds.java | 2 - .../LdapAuthenticationProviderConfigurer.java | 18 +- .../ldap/LdapServerBeanDefinitionParser.java | 30 +- .../security/config/spring-security-7.0.rnc | 4 +- .../security/config/spring-security-7.0.xsd | 3 +- ...ntextConfigurationResourceServerTests.java | 4 +- .../config/doc/XsdDocumentedTests.java | 6 +- config/src/test/resources/logback-test.xml | 2 - .../spring-security-dependencies.gradle | 6 - docs/modules/ROOT/pages/modules.adoc | 10 +- .../ROOT/pages/servlet/appendix/faq.adoc | 53 +-- .../servlet/appendix/namespace/ldap.adoc | 2 +- .../authentication/passwords/ldap.adoc | 78 +--- .../servlet/configuration/xml-namespace.adoc | 2 +- docs/spring-security-docs.gradle | 1 - gradle/libs.versions.toml | 7 - ...test-ldap-embedded-apacheds-default.gradle | 30 -- .../LdapServerBeanDefinitionParserTests.java | 56 --- .../resources/applicationContext-security.xml | 9 - .../src/integration-test/resources/users.ldif | 60 --- ...y-itest-ldap-embedded-mode-apacheds.gradle | 30 -- .../LdapServerBeanDefinitionParserTests.java | 56 --- .../resources/applicationContext-security.xml | 9 - .../src/integration-test/resources/users.ldif | 60 --- ldap/spring-security-ldap.gradle | 6 - ...faultSpringSecurityContextSourceTests.java | 2 +- .../SpringSecurityLdapTemplateITests.java | 12 +- ...fig.java => UnboundIdContainerConfig.java} | 16 +- .../BindAuthenticatorTests.java | 4 +- .../PasswordComparisonAuthenticatorTests.java | 4 +- .../FilterBasedLdapUserSearchTests.java | 4 +- ...terBasedLdapUserSearchWithSpacesTests.java | 16 +- .../ldap/server/ApacheDSContainerTests.java | 221 ----------- .../server/ApacheDSEmbeddedLdifTests.java | 79 ---- ...esPopulatorGetGrantedAuthoritiesTests.java | 16 +- .../DefaultLdapAuthoritiesPopulatorTests.java | 4 +- .../LdapUserDetailsManagerTests.java | 4 +- .../NestedLdapAuthoritiesPopulatorTests.java | 4 +- .../ldap/server/ApacheDSContainer.java | 365 ------------------ .../security/ldap/server/package-info.java | 3 +- .../server/core/avltree/ArrayMarshaller.java | 173 --------- ...ectoryLdapAuthenticationProviderTests.java | 3 +- 49 files changed, 138 insertions(+), 1406 deletions(-) delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml delete mode 100644 itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml delete mode 100644 itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif rename ldap/src/integration-test/java/org/springframework/security/ldap/{ApacheDsContainerConfig.java => UnboundIdContainerConfig.java} (67%) delete mode 100644 ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java delete mode 100644 ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java delete mode 100644 ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java delete mode 100644 ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java diff --git a/config/spring-security-config.gradle b/config/spring-security-config.gradle index 83f91c9bf0..322f77af47 100644 --- a/config/spring-security-config.gradle +++ b/config/spring-security-config.gradle @@ -78,12 +78,6 @@ dependencies { exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'xml-apis', module: 'xml-apis' } - testImplementation "org.apache.directory.server:apacheds-core" - testImplementation "org.apache.directory.server:apacheds-core-entry" - testImplementation "org.apache.directory.server:apacheds-protocol-shared" - testImplementation "org.apache.directory.server:apacheds-protocol-ldap" - testImplementation "org.apache.directory.server:apacheds-server-jndi" - testImplementation 'org.apache.directory.shared:shared-ldap' testImplementation "com.unboundid:unboundid-ldapsdk" testImplementation 'jakarta.persistence:jakarta.persistence-api' testImplementation "org.hibernate.orm:hibernate-core" diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java index 17362f02ae..890ed32048 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java @@ -44,7 +44,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; @@ -326,11 +326,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests { abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig { @Bean - ApacheDSContainer ldapServer() throws Exception { - ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", + UnboundIdContainer ldapServer() throws Exception { + UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); - apacheDSContainer.setPort(getPort()); - return apacheDSContainer; + unboundIdContainer.setPort(getPort()); + return unboundIdContainer; } } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java index 9496ba2651..25c02eb69a 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapBindAuthenticationManagerFactoryITests.java @@ -43,7 +43,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; @@ -226,18 +226,18 @@ public class LdapBindAuthenticationManagerFactoryITests { @EnableWebSecurity abstract static class BaseLdapServerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapServer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); + UnboundIdContainer ldapServer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - BaseLdapPathContextSource contextSource(ApacheDSContainer container) { - int port = container.getLocalPort(); + BaseLdapPathContextSource contextSource(UnboundIdContainer container) { + int port = container.getPort(); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java index 668fe9b994..fd0ace02aa 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapPasswordComparisonAuthenticationManagerFactoryITests.java @@ -31,7 +31,7 @@ import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; @@ -93,18 +93,18 @@ public class LdapPasswordComparisonAuthenticationManagerFactoryITests { @EnableWebSecurity abstract static class BaseLdapServerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapServer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); + UnboundIdContainer ldapServer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - BaseLdapPathContextSource contextSource(ApacheDSContainer container) { - int port = container.getLocalPort(); + BaseLdapPathContextSource contextSource(UnboundIdContainer container) { + int port = container.getPort(); return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org"); } diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java index 162fcc8495..a992de947e 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParserTests.java @@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests { AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class); Authentication auth = authenticationManager - .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword")); + .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("otherben", "otherbenspassword")); UserDetails ben = (UserDetails) auth.getPrincipal(); assertThat(ben.getAuthorities()).hasSize(3); } @@ -127,6 +127,27 @@ public class LdapProviderBeanDefinitionParserTests { assertThat(auth).isNotNull(); } + @Test + public void supportsShaPasswordEncoder() { + this.appCtx = new InMemoryXmlApplicationContext(""" + + + + + + + + + + """); + AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, + AuthenticationManager.class); + Authentication auth = authenticationManager + .authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword")); + + assertThat(auth).isNotNull(); + } + @Test public void inetOrgContextMapperIsSupported() { this.appCtx = new InMemoryXmlApplicationContext( diff --git a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java index cf5a5b16bd..c453fe1cef 100644 --- a/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java +++ b/config/src/integration-test/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParserTests.java @@ -26,7 +26,7 @@ import org.springframework.ldap.core.LdapTemplate; import org.springframework.security.config.BeanIds; import org.springframework.security.config.util.InMemoryXmlApplicationContext; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -92,9 +92,9 @@ public class LdapServerBeanDefinitionParserTests { @Test public void defaultLdifFileIsSuccessful() { this.appCtx = new InMemoryXmlApplicationContext(""); - ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class); + UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class); - assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif"); + assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif"); } private int getDefaultPort() throws IOException { diff --git a/config/src/integration-test/resources/logback-test.xml b/config/src/integration-test/resources/logback-test.xml index 473e666748..1024d52dec 100644 --- a/config/src/integration-test/resources/logback-test.xml +++ b/config/src/integration-test/resources/logback-test.xml @@ -7,7 +7,6 @@ - diff --git a/config/src/main/java/org/springframework/security/config/BeanIds.java b/config/src/main/java/org/springframework/security/config/BeanIds.java index fcf2e5fc1d..da398cac57 100644 --- a/config/src/main/java/org/springframework/security/config/BeanIds.java +++ b/config/src/main/java/org/springframework/security/config/BeanIds.java @@ -54,8 +54,6 @@ public abstract class BeanIds { public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor"; - public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer"; - public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer"; public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource"; diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java index c54d6378ec..0f47afa594 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java @@ -37,7 +37,6 @@ import org.springframework.security.ldap.authentication.LdapAuthenticator; import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.ldap.search.LdapUserSearch; -import org.springframework.security.ldap.server.ApacheDSContainer; import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper; @@ -60,12 +59,8 @@ import org.springframework.util.ClassUtils; public class LdapAuthenticationProviderConfigurer> extends SecurityConfigurerAdapter { - private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService"; - private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer"; - private static final boolean apacheDsPresent; - private static final boolean unboundIdPresent; private String groupRoleAttribute = "cn"; @@ -100,7 +95,6 @@ public class LdapAuthenticationProviderConfigurer with no Id), that server will be used. diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd index 4ff414800b..676b55a13d 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-7.0.xsd @@ -224,13 +224,12 @@ - Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and + Explicitly specifies which embedded ldap server should use. The only supported value is 'unboundid'. By default, it will depends if the library is available in the classpath. - diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java index 95f85c9be4..76001a2fac 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java @@ -21,7 +21,6 @@ import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; -import org.apache.commons.lang.StringUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,6 +38,7 @@ import org.springframework.security.oauth2.server.resource.web.reactive.function import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; @@ -197,7 +197,7 @@ public class SecurityReactorContextConfigurationResourceServerTests { public MockResponse dispatch(RecordedRequest request) { MockResponse response = new MockResponse().setResponseCode(200); String header = request.getHeader("Authorization"); - if (StringUtils.isBlank(header)) { + if (!StringUtils.hasText(header)) { return response; } return response.setBody(header); diff --git a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java index ccab6cb535..5607501eda 100644 --- a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java +++ b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java @@ -30,12 +30,12 @@ import java.util.TreeMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang.StringUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.security.config.http.SecurityFiltersAssertions; +import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -86,7 +86,7 @@ public class XsdDocumentedTests { .flatMap(XmlNode::children) .flatMap(XmlNode::children) .map((node) -> node.attribute("value")) - .filter(StringUtils::isNotEmpty) + .filter(StringUtils::hasText) .collect(Collectors.toList()); // @formatter:on SecurityFiltersAssertions.assertEquals(nodes); @@ -129,7 +129,7 @@ public class XsdDocumentedTests { .flatMap(XmlNode::children) .flatMap(XmlNode::children) .map((node) -> node.attribute("value")) - .filter(StringUtils::isNotEmpty) + .filter(StringUtils::hasText) .collect(Collectors.toList()); // @formatter:on assertThat(nodes).isEqualTo(expected); diff --git a/config/src/test/resources/logback-test.xml b/config/src/test/resources/logback-test.xml index fc35a34be1..e107f50bc8 100644 --- a/config/src/test/resources/logback-test.xml +++ b/config/src/test/resources/logback-test.xml @@ -7,8 +7,6 @@ - - diff --git a/dependencies/spring-security-dependencies.gradle b/dependencies/spring-security-dependencies.gradle index 2a2d433252..1a8be3ff73 100644 --- a/dependencies/spring-security-dependencies.gradle +++ b/dependencies/spring-security-dependencies.gradle @@ -49,12 +49,6 @@ dependencies { api libs.ldapsdk api libs.net.sourceforge.htmlunit api libs.org.htmlunit.htmlunit - api libs.org.apache.directory.server.apacheds.entry - api libs.org.apache.directory.server.apacheds.core - api libs.org.apache.directory.server.apacheds.protocol.ldap - api libs.org.apache.directory.server.apacheds.protocol.shared - api libs.org.apache.directory.server.apacheds.server.jndi - api libs.org.apache.directory.shared.shared.ldap api libs.org.apache.httpcomponents.httpclient api libs.org.aspectj.aspectjrt api libs.org.aspectj.aspectjweaver diff --git a/docs/modules/ROOT/pages/modules.adoc b/docs/modules/ROOT/pages/modules.adoc index df36c89014..12c2fca3b1 100644 --- a/docs/modules/ROOT/pages/modules.adoc +++ b/docs/modules/ROOT/pages/modules.adoc @@ -166,13 +166,9 @@ The top-level package is `org.springframework.security.ldap`. | | Data exception classes are required. -| apache-ds -| 1.5.5 -| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required. - -| shared-ldap -| 0.9.15 -| Required if you are using an embedded LDAP server (optional). +| com.unboundid:unboundid-ldapsdk +| +| Required if using an embedded LDAP server | ldapsdk | 4.1 diff --git a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc index d987b67642..0c72852891 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc @@ -363,7 +363,7 @@ This section addresses common Spring Security architecture questions: . <> . <> . <> -. <> +. <> . <> @@ -412,30 +412,39 @@ The reference manual also includes <> that lists If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. +[[appendix-faq-unboundid-deps]] +=== What dependences are needed to run an embedded UnboundID LDAP server? + +You need to add the following dependency to your project: + +[tabs] +====== +Maven:: ++ +[source,maven,role="primary"] +---- + + com.unboundid + unboundid-ldapsdk + 7.0.1 + runtime + +---- + +Gradle:: ++ +[source,gradle,role="secondary"] +---- +implementation 'com.unboundid:unboundid-ldapsdk:7.0.1' +---- +====== + + [[appendix-faq-apacheds-deps]] === What dependencies are needed to run an embedded ApacheDS LDAP server? -If you use Maven, you need to add the following to your `pom.xml` file dependencies: - -[source] ----- - - - org.apache.directory.server - apacheds-core - 1.5.5 - runtime - - - org.apache.directory.server - apacheds-server-jndi - 1.5.5 - runtime - - ----- - -The other required jars should be pulled in transitively. +Spring Security 7 removes support for Apache DS. +Please use <> instead. [[appendix-faq-what-is-userdetailservice]] === What is a UserDetailsService and do I need one? diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc index f3c07e6d76..819189b0b3 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/ldap.adoc @@ -24,7 +24,7 @@ This is actually the bean `id` of the `ContextSource` instance, if you want to u [[nsa-ldap-server-mode]] * **mode** -Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath. +Explicitly specifies which embedded ldap server should use. The only supported value is `unboundid`. By default, it will depends if the library is available in the classpath. [[nsa-ldap-server-id]] * **id** diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc index de64a1d448..1ee0668e7a 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc @@ -223,82 +223,8 @@ fun ldapContainer(): UnboundIdContainer { [[servlet-authentication-ldap-apacheds]] === Embedded ApacheDS Server -[NOTE] -==== -Spring Security uses ApacheDS 1.x, which is no longer maintained. -Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. -Once a stable release of ApacheDS 2.x is available, we will consider updating. -==== - -If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: - -.ApacheDS Dependencies -[tabs] -====== -Maven:: -+ -[source,xml,role="primary",subs="+attributes"] ----- - - org.apache.directory.server - apacheds-core - {apacheds-core-version} - runtime - - - org.apache.directory.server - apacheds-server-jndi - {apacheds-core-version} - runtime - ----- - -Gradle:: -+ -[source,groovy,role="secondary",subs="+attributes"] ----- -depenendencies { - runtimeOnly "org.apache.directory.server:apacheds-core:{apacheds-core-version}" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi:{apacheds-core-version}" -} ----- -====== - -You can then configure the Embedded LDAP Server: - -.Embedded LDAP Server Configuration -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Bean -ApacheDSContainer ldapContainer() { - return new ApacheDSContainer("dc=springframework,dc=org", - "classpath:users.ldif"); -} ----- - -XML:: -+ -[source,xml,role="secondary"] ----- - ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Bean -fun ldapContainer(): ApacheDSContainer { - return ApacheDSContainer("dc=springframework,dc=org", "classpath:users.ldif") -} ----- -====== +Spring Security 7 removes support for Apache DS. +Please use <> instead. [[servlet-authentication-ldap-contextsource]] == LDAP ContextSource diff --git a/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc b/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc index e6f2ed028d..ddf652799c 100644 --- a/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc +++ b/docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc @@ -15,7 +15,7 @@ For example, adding the following element from the `security` namespace to an ap ---- -This is much simpler than wiring up the equivalent Apache Directory Server beans. +This is much simpler than wiring up the equivalent UnboundID Server beans. The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are. You can find out more about the use of the `ldap-server` element in the chapter on xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap[LDAP Authentication]. A good XML editor while editing the application context file should provide information on the attributes and elements that are available. diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index 680ab725e9..23e8d0db91 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -45,7 +45,6 @@ dependencies { testImplementation libs.webauthn4j.core testImplementation 'org.jetbrains.kotlin:kotlin-reflect' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - testImplementation 'org.apache.directory.server:apacheds-core' testImplementation 'org.springframework:spring-core' testImplementation 'org.springframework:spring-test' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1969124ad4..acd27bc3f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,6 @@ io-rsocket = "1.1.5" io-spring-javaformat = "0.0.46" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" -org-apache-directory-server = "1.5.5" org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.80" @@ -50,12 +49,6 @@ jakarta-xml-bind-jakarta-xml-bind-api = "jakarta.xml.bind:jakarta.xml.bind-api:4 ldapsdk = "ldapsdk:ldapsdk:4.1" net-sourceforge-htmlunit = "net.sourceforge.htmlunit:htmlunit:2.70.0" org-htmlunit-htmlunit = "org.htmlunit:htmlunit:4.11.1" -org-apache-directory-server-apacheds-core = { module = "org.apache.directory.server:apacheds-core", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-entry = { module = "org.apache.directory.server:apacheds-core-entry", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-protocol-ldap = { module = "org.apache.directory.server:apacheds-protocol-ldap", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.directory.server:apacheds-protocol-shared", version.ref = "org-apache-directory-server" } -org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" } -org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15" org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14" org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10" org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" } diff --git a/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle b/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle deleted file mode 100644 index b48ab908a9..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/spring-security-itest-ldap-embedded-apacheds-default.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'io.spring.convention.spring-test' - -dependencies { - implementation platform(project(":spring-security-dependencies")) - implementation project(':spring-security-core') - implementation 'org.springframework:spring-beans' - implementation 'org.springframework:spring-context' - implementation 'org.springframework:spring-core' - implementation 'org.springframework:spring-tx' - implementation project(':spring-security-config') - implementation project(':spring-security-ldap') - - runtimeOnly "org.apache.directory.server:apacheds-core" - runtimeOnly "org.apache.directory.server:apacheds-core-entry" - runtimeOnly "org.apache.directory.server:apacheds-protocol-shared" - runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi" - runtimeOnly 'org.apache.directory.shared:shared-ldap' - - testImplementation project(path : ':spring-security-ldap', configuration : 'tests') - testImplementation "org.assertj:assertj-core" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.junit.jupiter:junit-jupiter-params" - testImplementation "org.junit.jupiter:junit-jupiter-engine" - testImplementation "org.mockito:mockito-core" - testImplementation "org.mockito:mockito-junit-jupiter" - testImplementation "org.springframework:spring-test" - - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java deleted file mode 100644 index 4f2be179a3..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.security.config.BeanIds; -import org.springframework.security.ldap.server.ApacheDSContainer; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -public class LdapServerBeanDefinitionParserTests { - - private ClassPathXmlApplicationContext context; - - @BeforeEach - public void setup() { - this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml"); - } - - @AfterEach - public void closeAppContext() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void apacheDirectoryServerIsStartedByDefault() { - String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class); - assertThat(beanNames).hasSize(1); - assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS); - } - -} diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml deleted file mode 100644 index b1b80079c5..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/applicationContext-security.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif b/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif deleted file mode 100644 index 222e03793c..0000000000 --- a/itest/ldap/embedded-ldap-apacheds-default/src/integration-test/resources/users.ldif +++ /dev/null @@ -1,60 +0,0 @@ -dn: ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: groups - -dn: ou=people,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: people - -dn: uid=rod,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Rod Johnson -sn: Johnson -uid: rod -userPassword: koala - -dn: uid=dianne,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Dianne Emu -sn: Emu -uid: dianne -userPassword: emu - -dn: uid=scott,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Scott -sn: Wombat -uid: scott -userPassword: wombat - -dn: cn=user,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: user -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org -member: uid=scott,ou=people,dc=springframework,dc=org - -dn: cn=teller,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: teller -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org - -dn: cn=supervisor,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: supervisor -member: uid=rod,ou=people,dc=springframework,dc=org diff --git a/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle b/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle deleted file mode 100644 index b48ab908a9..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/spring-security-itest-ldap-embedded-mode-apacheds.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'io.spring.convention.spring-test' - -dependencies { - implementation platform(project(":spring-security-dependencies")) - implementation project(':spring-security-core') - implementation 'org.springframework:spring-beans' - implementation 'org.springframework:spring-context' - implementation 'org.springframework:spring-core' - implementation 'org.springframework:spring-tx' - implementation project(':spring-security-config') - implementation project(':spring-security-ldap') - - runtimeOnly "org.apache.directory.server:apacheds-core" - runtimeOnly "org.apache.directory.server:apacheds-core-entry" - runtimeOnly "org.apache.directory.server:apacheds-protocol-shared" - runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap" - runtimeOnly "org.apache.directory.server:apacheds-server-jndi" - runtimeOnly 'org.apache.directory.shared:shared-ldap' - - testImplementation project(path : ':spring-security-ldap', configuration : 'tests') - testImplementation "org.assertj:assertj-core" - testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.junit.jupiter:junit-jupiter-params" - testImplementation "org.junit.jupiter:junit-jupiter-engine" - testImplementation "org.mockito:mockito-core" - testImplementation "org.mockito:mockito-junit-jupiter" - testImplementation "org.springframework:spring-test" - - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java deleted file mode 100644 index 4f2be179a3..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/java/org/springframework/security/LdapServerBeanDefinitionParserTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.security.config.BeanIds; -import org.springframework.security.ldap.server.ApacheDSContainer; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -public class LdapServerBeanDefinitionParserTests { - - private ClassPathXmlApplicationContext context; - - @BeforeEach - public void setup() { - this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml"); - } - - @AfterEach - public void closeAppContext() { - if (this.context != null) { - this.context.close(); - this.context = null; - } - } - - @Test - public void apacheDirectoryServerIsStartedByDefault() { - String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class); - assertThat(beanNames).hasSize(1); - assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS); - } - -} diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml deleted file mode 100644 index 8e3f4b4380..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/applicationContext-security.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif b/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif deleted file mode 100644 index 222e03793c..0000000000 --- a/itest/ldap/embedded-ldap-mode-apacheds/src/integration-test/resources/users.ldif +++ /dev/null @@ -1,60 +0,0 @@ -dn: ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: groups - -dn: ou=people,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: people - -dn: uid=rod,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Rod Johnson -sn: Johnson -uid: rod -userPassword: koala - -dn: uid=dianne,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Dianne Emu -sn: Emu -uid: dianne -userPassword: emu - -dn: uid=scott,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Scott -sn: Wombat -uid: scott -userPassword: wombat - -dn: cn=user,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: user -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org -member: uid=scott,ou=people,dc=springframework,dc=org - -dn: cn=teller,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: teller -member: uid=rod,ou=people,dc=springframework,dc=org -member: uid=dianne,ou=people,dc=springframework,dc=org - -dn: cn=supervisor,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: supervisor -member: uid=rod,ou=people,dc=springframework,dc=org diff --git a/ldap/spring-security-ldap.gradle b/ldap/spring-security-ldap.gradle index d15029ffdd..f816af7ab8 100644 --- a/ldap/spring-security-ldap.gradle +++ b/ldap/spring-security-ldap.gradle @@ -15,12 +15,6 @@ dependencies { optional 'com.fasterxml.jackson.core:jackson-databind' optional 'ldapsdk:ldapsdk' optional "com.unboundid:unboundid-ldapsdk" - optional "org.apache.directory.server:apacheds-core" - optional "org.apache.directory.server:apacheds-core-entry" - optional "org.apache.directory.server:apacheds-protocol-shared" - optional "org.apache.directory.server:apacheds-protocol-ldap" - optional "org.apache.directory.server:apacheds-server-jndi" - optional 'org.apache.directory.shared:shared-ldap' api ('org.springframework.ldap:spring-ldap-core') { exclude(group: 'commons-logging', module: 'commons-logging') exclude(group: 'org.springframework', module: 'spring-beans') diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java index 607b0a2414..f03af31b4d 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java @@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class DefaultSpringSecurityContextSourceTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java index 5b7ca9f69f..25d65e1215 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateITests.java @@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class SpringSecurityLdapTemplateITests { @Autowired @@ -116,10 +116,10 @@ public class SpringSecurityLdapTemplateITests { assertThat(values).hasSize(1); Map> record = values.iterator().next(); assertAttributeValue(record, "uid", "bob"); - assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"); + assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson"); assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); - assertThat(record.containsKey("userPassword")).isFalse(); + assertThat(record.containsKey("userPassword")).isTrue(); } @Test @@ -129,10 +129,10 @@ public class SpringSecurityLdapTemplateITests { assertThat(values).hasSize(1); Map> record = values.iterator().next(); assertAttributeValue(record, "uid", "bob"); - assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson"); + assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson"); assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); - assertThat(record.containsKey("userPassword")).isFalse(); + assertThat(record.containsKey("userPassword")).isTrue(); } @Test @@ -145,7 +145,7 @@ public class SpringSecurityLdapTemplateITests { assertAttributeValue(record, "cn", "Bob Hamilton"); assertAttributeValue(record, "sn", "Hamilton"); assertThat(record.containsKey("userPassword")).isFalse(); - assertThat(record.containsKey("objectclass")).isFalse(); + assertThat(record.containsKey("objectClass")).isFalse(); } protected void assertAttributeValue(Map> record, String attributeName, String... values) { diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java b/ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java similarity index 67% rename from ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java rename to ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java index 41478863d6..b56abddd62 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/ApacheDsContainerConfig.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/UnboundIdContainerConfig.java @@ -20,31 +20,31 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.ContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; /** * @author Eddú Meléndez */ @Configuration -public class ApacheDsContainerConfig implements DisposableBean { +public class UnboundIdContainerConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) throws Exception { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org"); } @Override - public void destroy() throws Exception { + public void destroy() { this.container.stop(); } diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java index 95e73bd217..46f6d71fb0 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/BindAuthenticatorTests.java @@ -33,8 +33,8 @@ import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.SpringSecurityMessageSource; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -53,7 +53,7 @@ import static org.mockito.Mockito.spy; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class BindAuthenticatorTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java index 5ba4a7d72c..a7598b3c4e 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/authentication/PasswordComparisonAuthenticatorTests.java @@ -30,8 +30,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.password.LdapShaPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class PasswordComparisonAuthenticatorTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java index 5dd196fb02..57b2f3bddb 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java @@ -25,8 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class FilterBasedLdapUserSearchTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java index 6db08933fa..9b790f711b 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchWithSpacesTests.java @@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Steve Riesenberg */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.ApacheDsContainerWithSpacesConfig.class) +@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.UnboundIdContainerWithSpacesConfig.class) public class FilterBasedLdapUserSearchWithSpacesTests { @Autowired @@ -61,22 +61,22 @@ public class FilterBasedLdapUserSearchWithSpacesTests { } @Configuration - static class ApacheDsContainerWithSpacesConfig implements DisposableBean { + static class UnboundIdContainerWithSpacesConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=spring framework,dc=org", + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=spring framework,dc=org", "classpath:test-server-with-spaces.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=spring%20framework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=spring%20framework,dc=org"); } @Override diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java deleted file mode 100644 index f4f3953a19..0000000000 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.ServerSocket; -import java.security.UnrecoverableKeyException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.junit.jupiter.api.io.TempDir; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.util.FileCopyUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.fail; - -/** - * Useful for debugging the container by itself. - * - * @author Luke Taylor - * @author Rob Winch - * @author Gunnar Hillert - * @author Evgeniy Cheban - * @since 3.0 - */ -public class ApacheDSContainerTests { - - @TempDir - public File temporaryFolder; - - // SEC-2162 - @Test - public void failsToStartThrowsException() throws Exception { - ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:missing.ldif"); - List ports = getDefaultPorts(1); - server1.setPort(ports.get(0)); - server2.setPort(ports.get(0)); - try { - server1.afterPropertiesSet(); - try { - server2.afterPropertiesSet(); - fail("Expected Exception"); - } - catch (RuntimeException success) { - } - } - finally { - try { - server1.destroy(); - } - catch (Throwable ex) { - } - try { - server2.destroy(); - } - catch (Throwable ex) { - } - } - } - - // SEC-2161 - @Test - public void multipleInstancesSimultanciously() throws Exception { - ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - List ports = getDefaultPorts(2); - server1.setPort(ports.get(0)); - server2.setPort(ports.get(1)); - try { - server1.afterPropertiesSet(); - server2.afterPropertiesSet(); - } - finally { - try { - server1.destroy(); - } - catch (Throwable ex) { - } - try { - server2.destroy(); - } - catch (Throwable ex) { - } - } - } - - @Test - public void startWithLdapOverSslWithoutCertificate() throws Exception { - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - server.setLdapOverSslEnabled(true); - assertThatIllegalArgumentException().isThrownBy(server::afterPropertiesSet) - .withMessage("When LdapOverSsl is enabled, the keyStoreFile property must be set."); - } - - @Test - @DisabledOnOs(OS.WINDOWS) - public void startWithLdapOverSslWithWrongPassword() throws Exception { - final ClassPathResource keyStoreResource = new ClassPathResource( - "/org/springframework/security/ldap/server/spring.keystore"); - final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore"); - FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile)); - - assertThat(temporaryKeyStoreFile).isFile(); - - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - - server.setLdapOverSslEnabled(true); - server.setKeyStoreFile(temporaryKeyStoreFile); - server.setCertificatePassord("incorrect-password"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(server::afterPropertiesSet) - .withMessage("Server startup failed") - .withRootCauseInstanceOf(UnrecoverableKeyException.class); - } - - /** - * This test starts an LDAP server using LDAPs (LDAP over SSL). A self-signed - * certificate is being used, which was previously generated with: - * - *

-	 * {@code
-	 * keytool -genkey -alias spring -keyalg RSA -keystore spring.keystore -validity 3650 -storetype JKS \
-	 * -dname "CN=localhost, OU=Spring, O=Pivotal, L=Kailua-Kona, ST=HI, C=US" -keypass spring -storepass spring
-	 * }
-	 * 
- * @throws Exception - */ - @Test - @DisabledOnOs(OS.WINDOWS) - public void startWithLdapOverSsl() throws Exception { - - final ClassPathResource keyStoreResource = new ClassPathResource( - "/org/springframework/security/ldap/server/spring.keystore"); - final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore"); - FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile)); - - assertThat(temporaryKeyStoreFile).isFile(); - - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - - List ports = getDefaultPorts(1); - server.setPort(ports.get(0)); - - server.setLdapOverSslEnabled(true); - server.setKeyStoreFile(temporaryKeyStoreFile); - server.setCertificatePassord("spring"); - - try { - server.afterPropertiesSet(); - } - finally { - try { - server.destroy(); - } - catch (Throwable ex) { - } - } - } - - private List getDefaultPorts(int count) throws IOException { - List connections = new ArrayList<>(); - List availablePorts = new ArrayList<>(count); - try { - for (int i = 0; i < count; i++) { - ServerSocket socket = new ServerSocket(0); - connections.add(socket); - availablePorts.add(socket.getLocalPort()); - } - return availablePorts; - } - finally { - for (ServerSocket conn : connections) { - conn.close(); - } - } - } - - @Test - public void afterPropertiesSetWhenPortIsZeroThenRandomPortIsSelected() throws Exception { - ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); - server.setPort(0); - try { - server.afterPropertiesSet(); - - assertThat(server.getPort()).isEqualTo(0); - assertThat(server.getLocalPort()).isNotEqualTo(0); - } - finally { - server.destroy(); - } - } - -} diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java deleted file mode 100644 index 232f241845..0000000000 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/server/ApacheDSEmbeddedLdifTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2002-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import org.springframework.ldap.core.support.LdapContextSource; -import org.springframework.security.ldap.SpringSecurityLdapTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests reproducing problems with loading structures from ldif on embedded ApacheDS - * server. - * - * @author Marcin Zajączkowski - */ -public class ApacheDSEmbeddedLdifTests { - - private static final String LDAP_ROOT = "ou=ssattributes,dc=springframework,dc=org"; - - private static final int LDAP_PORT = 52389; - - private ApacheDSContainer server; - - private SpringSecurityLdapTemplate ldapTemplate; - - @BeforeEach - public void setUp() throws Exception { - // TODO: InMemoryXmlApplicationContext would be useful here, but it is not visible - this.server = new ApacheDSContainer(LDAP_ROOT, "classpath:test-server-custom-attribute-types.ldif"); - this.server.setPort(LDAP_PORT); - this.server.afterPropertiesSet(); - - this.ldapTemplate = new SpringSecurityLdapTemplate(createLdapContextSource()); - } - - private LdapContextSource createLdapContextSource() { - LdapContextSource ldapContextSource = new LdapContextSource(); - ldapContextSource.setUrl("ldap://localhost:" + LDAP_PORT); - ldapContextSource.setBase(LDAP_ROOT); - ldapContextSource.afterPropertiesSet(); - return ldapContextSource; - } - - @AfterEach - public void tearDown() throws Exception { - if (this.server != null) { - this.server.destroy(); - } - } - - @Disabled // Not fixed yet - @Test // SEC-2387 - public void customAttributeTypesShouldBeProperlyCreatedWhenLoadedFromLdif() { - assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "uid", "objectWithCustomAttribute1")) - .isTrue(); - assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "customAttribute", "I am custom")) - .isTrue(); - } - -} diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java index 95181b7651..f48f4c90b6 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.java @@ -31,7 +31,7 @@ import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; -import org.springframework.security.ldap.server.ApacheDSContainer; +import org.springframework.security.ldap.server.UnboundIdContainer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @ExtendWith(SpringExtension.class) @ContextConfiguration( - classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.ApacheDsContainerWithUndefinedGroupRoleAttributeConfig.class) + classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.UnboundIdContainerWithUndefinedGroupRoleAttributeConfig.class) public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests { @Autowired @@ -77,22 +77,22 @@ public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests { } @Configuration - static class ApacheDsContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean { + static class UnboundIdContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean { - private ApacheDSContainer container; + private UnboundIdContainer container; @Bean - ApacheDSContainer ldapContainer() throws Exception { - this.container = new ApacheDSContainer("dc=springframework,dc=org", + UnboundIdContainer ldapContainer() { + this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server-with-undefined-group-role-attributes.ldif"); this.container.setPort(0); return this.container; } @Bean - ContextSource contextSource(ApacheDSContainer ldapContainer) { + ContextSource contextSource(UnboundIdContainer ldapContainer) { return new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org"); + "ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org"); } @Override diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java index 1d6e2d6664..a7fc6aafc5 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java @@ -31,8 +31,8 @@ import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) @SuppressWarnings({ "deprecation" }) public class DefaultLdapAuthoritiesPopulatorTests { diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java index 0a53171efb..df1f8b6e39 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsManagerTests.java @@ -34,9 +34,9 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.ldap.ApacheDsContainerConfig; import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper; import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,7 +52,7 @@ import static org.mockito.Mockito.verify; * @author Roman Zabaluev */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class LdapUserDetailsManagerTests { @Autowired diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java index aec53f235c..3139673b43 100644 --- a/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java +++ b/ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulatorTests.java @@ -28,7 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.ldap.ApacheDsContainerConfig; +import org.springframework.security.ldap.UnboundIdContainerConfig; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Eddú Meléndez */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = ApacheDsContainerConfig.class) +@ContextConfiguration(classes = UnboundIdContainerConfig.class) public class NestedLdapAuthoritiesPopulatorTests { @Autowired diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java b/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java deleted file mode 100644 index 1fe397ac51..0000000000 --- a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.ldap.server; - -import java.io.File; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.directory.server.core.DefaultDirectoryService; -import org.apache.directory.server.core.authn.AuthenticationInterceptor; -import org.apache.directory.server.core.entry.ServerEntry; -import org.apache.directory.server.core.exception.ExceptionInterceptor; -import org.apache.directory.server.core.interceptor.Interceptor; -import org.apache.directory.server.core.normalization.NormalizationInterceptor; -import org.apache.directory.server.core.operational.OperationalAttributeInterceptor; -import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition; -import org.apache.directory.server.core.referral.ReferralInterceptor; -import org.apache.directory.server.core.subtree.SubentryInterceptor; -import org.apache.directory.server.ldap.LdapServer; -import org.apache.directory.server.protocol.shared.store.LdifFileLoader; -import org.apache.directory.server.protocol.shared.transport.TcpTransport; -import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException; -import org.apache.directory.shared.ldap.name.LdapDN; -import org.apache.mina.transport.socket.SocketAcceptor; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.Lifecycle; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.util.Assert; - -/** - * Provides lifecycle services for the embedded apacheDS server defined by the supplied - * configuration. Used by {@code LdapServerBeanDefinitionParser}. An instance will be - * stored in the application context for each embedded server instance. It will start the - * server when the context is initialized and shut it down when it is closed. It is - * intended for temporary embedded use and will not retain changes across start/stop - * boundaries. The working directory is deleted on shutdown. - * - *

- * If used repeatedly in a single JVM process with the same configuration (for example, - * when repeatedly loading an application context during testing), it's important that the - * application context is closed to allow the bean to be disposed of and the server - * shutdown prior to attempting to start it again. - *

- * This class is intended for testing and internal security namespace use, only, and is - * not considered part of the framework's public API. - * - * @author Luke Taylor - * @author Rob Winch - * @author Gunnar Hillert - * @author Evgeniy Cheban - * @deprecated For removal in 7.0. Use {@link UnboundIdContainer} instead because ApacheDS - * 1.x is no longer supported with no GA version to replace it. - */ -@Deprecated(since = "5.2", forRemoval = true) -public class ApacheDSContainer - implements EmbeddedLdapServerContainer, InitializingBean, DisposableBean, Lifecycle, ApplicationContextAware { - - private final Log logger = LogFactory.getLog(getClass()); - - final DefaultDirectoryService service; - - LdapServer server; - - private TcpTransport transport; - - private ApplicationContext ctxt; - - private File workingDir; - - private boolean running; - - private final String ldifResources; - - private final JdbmPartition partition; - - private final String root; - - private int port = 53389; - - private int localPort; - - private boolean ldapOverSslEnabled; - - private File keyStoreFile; - - private String certificatePassord; - - public ApacheDSContainer(String root, String ldifs) throws Exception { - this.ldifResources = ldifs; - this.service = new DefaultDirectoryService(); - List list = new ArrayList<>(); - list.add(new NormalizationInterceptor()); - list.add(new AuthenticationInterceptor()); - list.add(new ReferralInterceptor()); - list.add(new ExceptionInterceptor()); - list.add(new OperationalAttributeInterceptor()); - list.add(new SubentryInterceptor()); - this.service.setInterceptors(list); - this.partition = new JdbmPartition(); - this.partition.setId("rootPartition"); - this.partition.setSuffix(root); - this.root = root; - this.service.addPartition(this.partition); - this.service.setExitVmOnShutdown(false); - this.service.setShutdownHookEnabled(false); - this.service.getChangeLog().setEnabled(false); - this.service.setDenormalizeOpAttrsEnabled(true); - } - - @Override - public void afterPropertiesSet() throws Exception { - if (this.workingDir == null) { - String apacheWorkDir = System.getProperty("apacheDSWorkDir"); - if (apacheWorkDir == null) { - apacheWorkDir = createTempDirectory("apacheds-spring-security-"); - } - setWorkingDirectory(new File(apacheWorkDir)); - } - Assert.isTrue(!this.ldapOverSslEnabled || this.keyStoreFile != null, - "When LdapOverSsl is enabled, the keyStoreFile property must be set."); - this.server = new LdapServer(); - this.server.setDirectoryService(this.service); - // AbstractLdapIntegrationTests assume IPv4, so we specify the same here - this.transport = new TcpTransport(this.port); - if (this.ldapOverSslEnabled) { - this.transport.setEnableSSL(true); - this.server.setKeystoreFile(this.keyStoreFile.getAbsolutePath()); - this.server.setCertificatePassword(this.certificatePassord); - } - this.server.setTransports(this.transport); - start(); - } - - @Override - public void destroy() { - stop(); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.ctxt = applicationContext; - } - - public void setWorkingDirectory(File workingDir) { - Assert.notNull(workingDir, "workingDir cannot be null"); - this.logger.info("Setting working directory for LDAP_PROVIDER: " + workingDir.getAbsolutePath()); - Assert.isTrue(!workingDir.exists(), - "The specified working directory '" + workingDir.getAbsolutePath() - + "' already exists. Another directory service instance may be using it or it may be from a " - + " previous unclean shutdown. Please confirm and delete it or configure a different " - + "working directory"); - this.workingDir = workingDir; - this.service.setWorkingDirectory(workingDir); - } - - @Override - public void setPort(int port) { - this.port = port; - } - - @Override - public int getPort() { - return this.port; - } - - /** - * Returns the port that is resolved by {@link TcpTransport}. - * @return the port that is resolved by {@link TcpTransport} - */ - public int getLocalPort() { - return this.localPort; - } - - /** - * If set to {@code true} will enable LDAP over SSL (LDAPs). If set to {@code true} - * {@link ApacheDSContainer#setCertificatePassord(String)} must be set as well. - * @param ldapOverSslEnabled If not set, will default to false - */ - public void setLdapOverSslEnabled(boolean ldapOverSslEnabled) { - this.ldapOverSslEnabled = ldapOverSslEnabled; - } - - /** - * The keyStore must not be null and must be a valid file. Will set the keyStore file - * on the underlying {@link LdapServer}. - * @param keyStoreFile Mandatory if LDAPs is enabled - */ - public void setKeyStoreFile(File keyStoreFile) { - Assert.notNull(keyStoreFile, "The keyStoreFile must not be null."); - Assert.isTrue(keyStoreFile.isFile(), "The keyStoreFile must be a file."); - this.keyStoreFile = keyStoreFile; - } - - /** - * Will set the certificate password on the underlying {@link LdapServer}. - * @param certificatePassord May be null - */ - public void setCertificatePassord(String certificatePassord) { - this.certificatePassord = certificatePassord; - } - - public DefaultDirectoryService getService() { - return this.service; - } - - @Override - public void start() { - if (isRunning()) { - return; - } - Assert.state(!this.service.isStarted(), "DirectoryService is already running."); - this.logger.info("Starting directory server..."); - try { - this.service.startup(); - this.server.start(); - } - catch (Exception ex) { - throw new RuntimeException("Server startup failed", ex); - } - try { - this.service.getAdminSession().lookup(this.partition.getSuffixDn()); - } - catch (LdapNameNotFoundException ex) { - handleLdapNameNotFoundException(); - } - catch (Exception ex) { - this.logger.error("Lookup failed", ex); - } - SocketAcceptor socketAcceptor = this.server.getSocketAcceptor(this.transport); - InetSocketAddress localAddress = socketAcceptor.getLocalAddress(); - this.localPort = localAddress.getPort(); - this.running = true; - try { - importLdifs(); - } - catch (Exception ex) { - throw new RuntimeException("Failed to import LDIF file(s)", ex); - } - } - - private void handleLdapNameNotFoundException() { - try { - LdapDN dn = new LdapDN(this.root); - Assert.isTrue(this.root.startsWith("dc="), "root must start with dc="); - String dc = this.root.substring(3, this.root.indexOf(',')); - ServerEntry entry = this.service.newEntry(dn); - entry.add("objectClass", "top", "domain", "extensibleObject"); - entry.add("dc", dc); - this.service.getAdminSession().add(entry); - } - catch (Exception ex) { - this.logger.error("Failed to create dc entry", ex); - } - } - - @Override - public void stop() { - if (!isRunning()) { - return; - } - this.logger.info("Shutting down directory server ..."); - try { - this.server.stop(); - this.service.shutdown(); - } - catch (Exception ex) { - this.logger.error("Shutdown failed", ex); - return; - } - this.running = false; - if (this.workingDir.exists()) { - this.logger.info("Deleting working directory " + this.workingDir.getAbsolutePath()); - deleteDir(this.workingDir); - } - } - - private void importLdifs() throws Exception { - // Import any ldif files - Resource[] ldifs = (this.ctxt != null) ? this.ctxt.getResources(this.ldifResources) - : new PathMatchingResourcePatternResolver().getResources(this.ldifResources); - // Note that we can't just import using the ServerContext returned - // from starting Apache DS, apparently because of the long-running issue - // DIRSERVER-169. - // We need a standard context. - // DirContext dirContext = contextSource.getReadWriteContext(); - if (ldifs == null || ldifs.length == 0) { - return; - } - Assert.isTrue(ldifs.length == 1, () -> "More than one LDIF resource found with the supplied pattern:" - + this.ldifResources + " Got " + Arrays.toString(ldifs)); - String ldifFile = getLdifFile(ldifs); - this.logger.info("Loading LDIF file: " + ldifFile); - LdifFileLoader loader = new LdifFileLoader(this.service.getAdminSession(), new File(ldifFile), null, - getClass().getClassLoader()); - loader.execute(); - } - - private String getLdifFile(Resource[] ldifs) throws IOException { - try { - return ldifs[0].getFile().getAbsolutePath(); - } - catch (IOException ex) { - return ldifs[0].getURI().toString(); - } - } - - private String createTempDirectory(String prefix) throws IOException { - String parentTempDir = System.getProperty("java.io.tmpdir"); - String fileNamePrefix = prefix + System.nanoTime(); - String fileName = fileNamePrefix; - for (int i = 0; i < 1000; i++) { - File tempDir = new File(parentTempDir, fileName); - if (!tempDir.exists()) { - return tempDir.getAbsolutePath(); - } - fileName = fileNamePrefix + "~" + i; - } - throw new IOException( - "Failed to create a temporary directory for file at " + new File(parentTempDir, fileNamePrefix)); - } - - private boolean deleteDir(File dir) { - if (dir.isDirectory()) { - String[] children = dir.list(); - for (String child : children) { - boolean success = deleteDir(new File(dir, child)); - if (!success) { - return false; - } - } - } - return dir.delete(); - } - - @Override - public boolean isRunning() { - return this.running; - } - -} diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java b/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java index eb33468157..52f0ab3da2 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java +++ b/ldap/src/main/java/org/springframework/security/ldap/server/package-info.java @@ -15,7 +15,6 @@ */ /** - * Embedded Apache Directory Server implementation, as used by the configuration - * namespace. + * Embedded UnboundID Server implementation, as used by the configuration namespace. */ package org.springframework.security.ldap.server; diff --git a/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java b/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java deleted file mode 100644 index c2d02fc9f2..0000000000 --- a/ldap/src/test/java/org/apache/directory/server/core/avltree/ArrayMarshaller.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.directory.server.core.avltree; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Comparator; - -import org.apache.directory.shared.ldap.util.StringTools; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to serialize the Array data. - * - * @author Apache Directory Project - * @version $Rev$, $Date$ - */ -@SuppressWarnings("unchecked") -public class ArrayMarshaller implements Marshaller> { - - /** static logger */ - private static final Logger LOG = LoggerFactory.getLogger(ArrayMarshaller.class); - - /** used for serialized form of an empty AvlTree */ - private static final byte[] EMPTY_TREE = new byte[1]; - - /** marshaller to be used for marshalling the keys */ - private Marshaller keyMarshaller; - - /** key Comparator for the AvlTree */ - private Comparator comparator; - - /** - * Creates a new instance of AvlTreeMarshaller with a custom key Marshaller. - * @param comparator Comparator to be used for key comparision - * @param keyMarshaller marshaller for keys - */ - public ArrayMarshaller(Comparator comparator, Marshaller keyMarshaller) { - this.comparator = comparator; - this.keyMarshaller = keyMarshaller; - } - - /** - * Creates a new instance of AvlTreeMarshaller with the default key Marshaller which - * uses Java Serialization. - * @param comparator Comparator to be used for key comparision - */ - public ArrayMarshaller(Comparator comparator) { - this.comparator = comparator; - this.keyMarshaller = DefaultMarshaller.INSTANCE; - } - - /** - * Marshals the given tree to bytes - * @param tree the tree to be marshalled - */ - public byte[] serialize(ArrayTree tree) { - if ((tree == null) || tree.isEmpty()) { - return EMPTY_TREE; - } - - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(byteStream); - byte[] data = null; - - try { - out.writeByte(0); // represents the start of an Array byte stream - out.writeInt(tree.size()); - - for (int position = 0; position < tree.size(); position++) { - E value = tree.get(position); - byte[] bytes = this.keyMarshaller.serialize(value); - - // Write the key length - out.writeInt(bytes.length); - - // Write the key if its length is not null - if (bytes.length != 0) { - out.write(bytes); - } - } - - out.flush(); - data = byteStream.toByteArray(); - - // Try to deserialize, just to see - try { - deserialize(data); - } - catch (NullPointerException npe) { - System.out.println("Bad serialization, tree : [" + StringTools.dumpBytes(data) + "]"); - throw npe; - } - - out.close(); - } - catch (IOException ex) { - ex.printStackTrace(); - } - - return data; - } - - /** - * Creates an Array from given bytes of data. - * @param data byte array to be converted into an array - */ - public ArrayTree deserialize(byte[] data) throws IOException { - try { - if ((data == null) || (data.length == 0)) { - throw new IOException("Null or empty data array is invalid."); - } - - if ((data.length == 1) && (data[0] == 0)) { - E[] array = (E[]) new Object[] {}; - ArrayTree tree = new ArrayTree(this.comparator, array); - return tree; - } - - ByteArrayInputStream bin = new ByteArrayInputStream(data); - DataInputStream din = new DataInputStream(bin); - - byte startByte = din.readByte(); - - if (startByte != 0) { - throw new IOException("wrong array serialized data format"); - } - - int size = din.readInt(); - E[] nodes = (E[]) new Object[size]; - - for (int i = 0; i < size; i++) { - // Read the object's size - int dataSize = din.readInt(); - - if (dataSize != 0) { - byte[] bytes = new byte[dataSize]; - - din.read(bytes); - E key = this.keyMarshaller.deserialize(bytes); - nodes[i] = key; - } - } - - ArrayTree arrayTree = new ArrayTree(this.comparator, nodes); - - return arrayTree; - } - catch (NullPointerException npe) { - System.out.println("Bad tree : [" + StringTools.dumpBytes(data) + "]"); - throw npe; - } - } - -} diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java index 6185ff81ca..0c10e1edd7 100644 --- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java +++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java @@ -29,7 +29,6 @@ import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; -import org.apache.directory.shared.ldap.util.EmptyEnumeration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -175,7 +174,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests { @Test public void noUserSearchCausesUsernameNotFound() throws Exception { given(this.ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class))) - .willReturn(new EmptyEnumeration<>()); + .willReturn(new MockNamingEnumeration(null)); this.provider.contextFactory = createContextFactoryReturning(this.ctx); assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.provider.authenticate(this.joe)); } From 09983e23494b13d1cba93d98c65a0c447720d750 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:47:30 -0600 Subject: [PATCH 397/504] Add ApacheDS Migration Steps Issue gh-13852 --- docs/modules/ROOT/pages/migration-7/ldap.adoc | 245 ++++++++++++++++++ .../ROOT/pages/servlet/appendix/faq.adoc | 35 ++- .../authentication/passwords/ldap.adoc | 5 +- 3 files changed, 281 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/migration-7/ldap.adoc b/docs/modules/ROOT/pages/migration-7/ldap.adoc index 3bef91f9ac..03c647e5a5 100644 --- a/docs/modules/ROOT/pages/migration-7/ldap.adoc +++ b/docs/modules/ROOT/pages/migration-7/ldap.adoc @@ -9,3 +9,248 @@ 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. + +To migrate, you will need to consider the following: + +1. <> +2. <> +3. <> +4. <> + +[[ldap-migrate-apacheds-unboundid-dependencies]] +=== Switch Your Dependencies + +To use UnboundID, you will at least need to remove the ApacheDS dependencies: + +[tabs] +====== +Maven:: ++ +[source,maven,role="primary"] +---- + + org.apache.directory.server + apacheds-core + 1.5.5 + runtime + + + org.apache.directory.server + apacheds-server-jndi + 1.5.5 + runtime + +---- + +Gradle:: ++ +[source,gradkle,role="secondary"] +---- +implementation("org.apache.directory.server:apacheds-server-jndi") +implementation("org.apache.directory.server:apacheds-core") +---- +====== + +and replace them with UnboundID: + +[tabs] +====== +Maven:: ++ +[source,maven,role="primary"] +---- + + com.unboundid + unboundid-ldapsdk + 7.0.3 + runtime + +---- + +Gradle:: ++ +[source,gradkle,role="secondary"] +---- +implementation("org.apache.directory.server:apacheds-server-jndi") +implementation("org.apache.directory.server:apacheds-core") +---- +====== + +If you are accepting the LDAP server defaults, this is likely all you will need to do. + +[[ldap-migrate-apacheds-unboundid-container]] +=== Change Server Declaration + +If you are declaring an ApacheDS server, then you will need to change its declaration. +Your configuration may vary somewhat from the following. +Change this: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +EmbeddedLdapServerContainer ldapContainer() { + EmbeddedLdapServerContainer container = + new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); + container.setPort(0); + return container; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun ldapContainer(): EmbeddedLdapServerContainer { + val container = + ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif") + container.setPort(0) + return container +} +---- + +Xml:: ++ +[source,xml,role="secondary"] +---- + +---- +====== + +to this: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +EmbeddedLdapServerContainer ldapContainer() { + EmbeddedLdapServerContainer container = + new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif"); + container.setPort(0); + return container; +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun ldapContainer(): EmbeddedLdapServerContainer { + val container = + UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif") + container.setPort(0) + return container +} +---- + +Xml:: ++ +[source,xml,role="secondary"] +---- + +---- +====== + + +[[ldap-migrate-apacheds-unboundid-password-encoding]] +=== Configure Password Encoding + +Apache Directory Server supports binding with SHA-hashed passwords, but UnboundID does not. + +If you run into trouble with binding users with SHA-hashed passwords, move to Spring Security's `PasswordComparisonAuthenticator` by providing a password encoder to the authentication provider: + +[tabs] +====== +Java:: ++ +[source,java,role="primary"] +---- +@Bean +AuthenticationManager ldapAuthenticationManager(BaseLdapPathContextSource contextSource) { + LdapPasswordComparisonAuthenticationManagerFactory factory = + new LdapPasswordComparisonAuthenticationManagerFactory( + contextSource, new LdapShaPasswordEncoder()); + // ... + return factory.createAuthenticationManager(); +} +---- + +Kotlin:: ++ +[source,kotlin,role="secondary"] +---- +@Bean +fun ldapAuthenticationManager(val contextSource: BaseLdapPathContextSource): AuthenticationManager { + val factory = LdapPasswordComparisonAuthenticationManagerFactory( + contextSource, LdapShaPasswordEncoder()) + // ... + return factory.createAuthenticationManager() +} +---- + +Xml:: ++ +[source,xml,role="secondary"] +---- + + + + + + + + +---- +====== + +[WARN] +==== +Hashing passwords with `+{SHA}+` is not recommended. +Please migrate to BCrypt, SCrypt, or Argon2 as soon as possible. +You can use the same approach above to provide the corresponding password encoder. +==== + +[[ldap-migrate-apacheds-unboundid-password-hiding]] +=== Configure Password Hiding + +ApacheDS is configured by Spring Security to hide the `userPassword` attribute from search results unless explicitly queried. +UnboundID does not support this. + +You can achieve this behavior with a custom `InMemoryOperationInterceptor` like the following: + +[source,java] +---- +static class PasswordRemovingOperationInterceptor + extends InMemoryOperationInterceptor { + + @Override + public void processSearchEntry(InMemoryInterceptedSearchEntry entry) { + if (!entry.getRequest().getAttributeList().contains("userPassword")) { + if (entry.getSearchEntry().getAttribute("userPassword") != null) { + Entry old = entry.getSearchEntry(); + Collection attributes = old.getAttributes().stream() + .filter(attribute -> + !"userPassword".equals(attribute.getName())) + .collect(Collectors.toList()); + Entry withoutPassword = new Entry(old.getDN(), attributes); + entry.setSearchEntry(withoutPassword); + } + } + } +} +---- + +[NOTE] +==== +It is better to secure passwords by hashing them and by using queries that identify the specific columns that you need. +==== + +`UnboundIdContainer` does not currently have a way to register a custom `InMemoryOperationInterceptor`, but you can either copy the contents of `UnboundIdContainer` or use Spring LDAP Test's `EmbeddedLdapServer` builder in order to provide this interceptor and confirm your application's readiness. diff --git a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc index d987b67642..af7f0a2a03 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/faq.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/faq.adoc @@ -363,7 +363,7 @@ This section addresses common Spring Security architecture questions: . <> . <> . <> -. <> +. <> . <> @@ -412,9 +412,42 @@ The reference manual also includes <> that lists If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires. Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them. +[[appendix-faq-unboundid-deps]] +=== What dependences are needed to run an embedded UnboundID LDAP server? + +You need to add the following dependency to your project: + +[tabs] +====== +Maven:: ++ +[source,maven,role="primary"] +---- + + com.unboundid + unboundid-ldapsdk + 7.0.1 + runtime + +---- + +Gradle:: ++ +[source,gradle,role="secondary"] +---- +implementation 'com.unboundid:unboundid-ldapsdk:7.0.1' +---- +====== + [[appendix-faq-apacheds-deps]] === What dependencies are needed to run an embedded ApacheDS LDAP server? +[NOTE] +==== +Spring Security 7 removes support for Apache DS. +Please use <> instead. +==== + If you use Maven, you need to add the following to your `pom.xml` file dependencies: [source] diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc index de64a1d448..d1d59ee013 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/ldap.adoc @@ -225,9 +225,8 @@ fun ldapContainer(): UnboundIdContainer { [NOTE] ==== -Spring Security uses ApacheDS 1.x, which is no longer maintained. -Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release. -Once a stable release of ApacheDS 2.x is available, we will consider updating. +Spring Security 7 removes support for Apache DS. +Please use <> instead. ==== If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies: From c43afbf5e1a1c7789411fbdf927a2ce733dff6a9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:34:48 -0600 Subject: [PATCH 398/504] Format Lambda Expressions This commit updats lambda expressions so that their variable is surrounded in parentheses. Issue gh-13067 --- .../ManagementConfigurationPlugin.java | 4 +- .../CheckExpectedBranchVersionPlugin.java | 2 +- .../authentication/password-storage.adoc | 2 +- .../authorize-http-requests.adoc | 2 +- .../pages/reactive/authorization/method.adoc | 2 +- .../pages/reactive/configuration/webflux.adoc | 2 +- .../ROOT/pages/reactive/exploits/csrf.adoc | 12 ++-- .../ROOT/pages/reactive/exploits/headers.adoc | 48 +++++++-------- .../ROOT/pages/reactive/exploits/http.adoc | 4 +- .../pages/reactive/integrations/cors.adoc | 2 +- .../pages/reactive/integrations/rsocket.adoc | 2 +- .../oauth2/client/authorization-grants.adoc | 18 +++--- .../pages/reactive/oauth2/client/index.adoc | 2 +- .../pages/reactive/oauth2/login/advanced.adoc | 10 ++-- .../pages/reactive/oauth2/login/core.adoc | 6 +- .../oauth2/resource-server/bearer-tokens.adoc | 4 +- .../reactive/oauth2/resource-server/jwt.adoc | 26 ++++----- .../oauth2/resource-server/multitenancy.adoc | 10 ++-- .../oauth2/resource-server/opaque-token.adoc | 28 ++++----- .../ROOT/pages/reactive/test/web/oauth2.adoc | 10 ++-- .../ROOT/pages/servlet/architecture.adoc | 2 +- .../authentication/passwords/digest.adoc | 2 +- .../authentication/passwords/form.adoc | 2 +- .../authentication/session-management.adoc | 14 ++--- .../authorize-http-requests.adoc | 6 +- .../pages/servlet/configuration/java.adoc | 28 ++++----- .../ROOT/pages/servlet/exploits/headers.adoc | 58 +++++++++---------- .../pages/servlet/integrations/websocket.adoc | 14 ++--- .../oauth2/client/authorization-grants.adoc | 28 ++++----- .../pages/servlet/oauth2/client/index.adoc | 4 +- .../pages/servlet/oauth2/login/advanced.adoc | 46 +++++++-------- .../ROOT/pages/servlet/oauth2/login/core.adoc | 6 +- .../pages/servlet/oauth2/login/logout.adoc | 4 +- .../oauth2/resource-server/bearer-tokens.adoc | 4 +- .../servlet/oauth2/resource-server/jwt.adoc | 30 +++++----- .../oauth2/resource-server/multitenancy.adoc | 14 ++--- .../oauth2/resource-server/opaque-token.adoc | 26 ++++----- .../saml2/login/authentication-requests.adoc | 4 +- .../servlet/saml2/login/authentication.adoc | 16 ++--- .../pages/servlet/saml2/login/overview.adoc | 20 +++---- .../pages/servlet/test/mockmvc/oauth2.adoc | 10 ++-- ...b-client-access-token-response-client.adoc | 2 +- .../reactivex509/CustomX509Configuration.java | 4 +- .../DefaultX509Configuration.java | 2 +- .../DefaultX509Configuration.java | 2 +- 45 files changed, 272 insertions(+), 272 deletions(-) diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java b/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java index 8db6fd970b..fcc8c06fb9 100644 --- a/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/ManagementConfigurationPlugin.java @@ -61,7 +61,7 @@ public class ManagementConfigurationPlugin implements Plugin { PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class); publishing.getPublications().withType(MavenPublication.class, (mavenPublication -> { mavenPublication.versionMapping((versions) -> - versions.allVariants(versionMapping -> versionMapping.fromResolutionResult()) + versions.allVariants((versionMapping) -> versionMapping.fromResolutionResult()) ); })); }); @@ -71,4 +71,4 @@ public class ManagementConfigurationPlugin implements Plugin { })); }); } -} \ No newline at end of file +} diff --git a/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java b/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java index bcff3306f0..346257aad3 100644 --- a/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java +++ b/buildSrc/src/main/java/org/springframework/security/CheckExpectedBranchVersionPlugin.java @@ -46,7 +46,7 @@ public class CheckExpectedBranchVersionPlugin implements Plugin { task.setDescription("Check if the project version matches the branch version"); task.onlyIf("skipCheckExpectedBranchVersion property is false or not present", CheckExpectedBranchVersionPlugin::skipPropertyFalseOrNotPresent); task.getVersion().convention(project.provider(() -> project.getVersion().toString())); - task.getBranchName().convention(project.getProviders().exec(execSpec -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText()); + task.getBranchName().convention(project.getProviders().exec((execSpec) -> execSpec.setCommandLine("git", "symbolic-ref", "--short", "HEAD")).getStandardOutput().getAsText()); task.getOutputFile().convention(project.getLayout().getBuildDirectory().file("check-expected-branch-version")); }); project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME, checkTask -> checkTask.dependsOn(checkExpectedBranchVersionTask)); diff --git a/docs/modules/ROOT/pages/features/authentication/password-storage.adoc b/docs/modules/ROOT/pages/features/authentication/password-storage.adoc index 94e2cf21e0..2ea6d68bab 100644 --- a/docs/modules/ROOT/pages/features/authentication/password-storage.adoc +++ b/docs/modules/ROOT/pages/features/authentication/password-storage.adoc @@ -615,7 +615,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin((login) -> login diff --git a/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc index c1e27d2309..21f678acf0 100644 --- a/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc @@ -15,7 +15,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) .httpBasic(withDefaults()) diff --git a/docs/modules/ROOT/pages/reactive/authorization/method.adoc b/docs/modules/ROOT/pages/reactive/authorization/method.adoc index 42a68da609..ebc83eef0a 100644 --- a/docs/modules/ROOT/pages/reactive/authorization/method.adoc +++ b/docs/modules/ROOT/pages/reactive/authorization/method.adoc @@ -614,7 +614,7 @@ public class SecurityConfig { return http // Demonstrate that method security works // Best practice to use both for defense in depth - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().permitAll() ) .httpBasic(withDefaults()) diff --git a/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc b/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc index 9c9575965b..158605ec42 100644 --- a/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc +++ b/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc @@ -87,7 +87,7 @@ public class HelloWebfluxSecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) .httpBasic(withDefaults()) diff --git a/docs/modules/ROOT/pages/reactive/exploits/csrf.adoc b/docs/modules/ROOT/pages/reactive/exploits/csrf.adoc index 5ec50d98a0..f4a1ca0d1e 100644 --- a/docs/modules/ROOT/pages/reactive/exploits/csrf.adoc +++ b/docs/modules/ROOT/pages/reactive/exploits/csrf.adoc @@ -45,7 +45,7 @@ Java:: public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())) + .csrf((csrf) -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())) return http.build(); } ----- @@ -91,7 +91,7 @@ Java:: public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .csrf(csrf -> csrf.disable())) + .csrf((csrf) -> csrf.disable())) return http.build(); } ---- @@ -133,7 +133,7 @@ Java:: public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .csrf(csrf -> csrf + .csrf((csrf) -> csrf .csrfTokenRequestHandler(new ServerCsrfTokenRequestAttributeHandler()) ) return http.build(); @@ -181,7 +181,7 @@ public class SecurityControllerAdvice { @ModelAttribute Mono csrfToken(ServerWebExchange exchange) { Mono csrfToken = exchange.getAttribute(CsrfToken.class.getName()); - return csrfToken.doOnSuccess(token -> exchange.getAttributes() + return csrfToken.doOnSuccess((token) -> token.getAttributes() .put(CsrfRequestDataValueProcessor.DEFAULT_CSRF_ATTR_NAME, token)); } } @@ -351,7 +351,7 @@ Java:: public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .logout(logout -> logout.requiresLogout(new PathPatternParserServerWebExchangeMatcher("/logout"))) + .logout((logout) -> logout.requiresLogout(new PathPatternParserServerWebExchangeMatcher("/logout"))) return http.build(); } ---- @@ -416,7 +416,7 @@ Java:: public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .csrf(csrf -> csrf.tokenFromMultipartDataEnabled(true)) + .csrf((csrf) -> csrf.tokenFromMultipartDataEnabled(true)) return http.build(); } ---- diff --git a/docs/modules/ROOT/pages/reactive/exploits/headers.adoc b/docs/modules/ROOT/pages/reactive/exploits/headers.adoc index e272b66d54..aed6658032 100644 --- a/docs/modules/ROOT/pages/reactive/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/reactive/exploits/headers.adoc @@ -26,8 +26,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions .mode(Mode.SAMEORIGIN) ) ); @@ -67,7 +67,7 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers.disable()); + .headers((headers) -> headers.disable()); return http.build(); } ---- @@ -112,8 +112,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .cache(cache -> cache.disable()) + .headers((headers) -> headers + .cache((cache) -> cache.disable()) ); return http.build(); } @@ -154,8 +154,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable()) + .headers((headers) -> headers + .contentTypeOptions((contentTypeOptions) -> contentTypeOptions.disable()) ); return http.build(); } @@ -196,8 +196,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .hsts(hsts -> hsts + .headers((headers) -> headers + .hsts((hsts) -> hsts .includeSubdomains(true) .preload(true) .maxAge(Duration.ofDays(365)) @@ -244,8 +244,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions .mode(SAMEORIGIN) ) ); @@ -287,8 +287,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .xssProtection(xssProtection -> xssProtection.disable()) + .headers((headers) -> headers + .xssProtection((xssProtection) -> xssProtection.disable()) ); return http.build(); } @@ -325,8 +325,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .xssProtection(xssProtection -> xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK)) + .headers((headers) -> headers + .xssProtection((xssProtection) -> xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK)) ); return http.build(); } @@ -376,8 +376,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .contentSecurityPolicy(policy -> policy + .headers((headers) -> headers + .contentSecurityPolicy((policy) -> policy .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") ) ); @@ -416,8 +416,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .contentSecurityPolicy(policy -> policy + .headers((headers) -> headers + .contentSecurityPolicy((policy) -> policy .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") .reportOnly() ) @@ -462,8 +462,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .referrerPolicy(referrer -> referrer + .headers((headers) -> headers + .referrerPolicy((referrer) -> referrer .policy(ReferrerPolicy.SAME_ORIGIN) ) ); @@ -515,7 +515,7 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers + .headers((headers) -> headers .featurePolicy("geolocation 'self'") ); return http.build(); @@ -564,8 +564,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .headers(headers -> headers - .permissionsPolicy(permissions -> permissions + .headers((headers) -> headers + .permissionsPolicy((permissions) -> permissions .policy("geolocation=(self)") ) ); diff --git a/docs/modules/ROOT/pages/reactive/exploits/http.adoc b/docs/modules/ROOT/pages/reactive/exploits/http.adoc index 68cf4db5cd..db4f3e57c7 100644 --- a/docs/modules/ROOT/pages/reactive/exploits/http.adoc +++ b/docs/modules/ROOT/pages/reactive/exploits/http.adoc @@ -57,8 +57,8 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .redirectToHttps(redirect -> redirect - .httpsRedirectWhen(e -> e.getRequest().getHeaders().containsKey("X-Forwarded-Proto")) + .redirectToHttps((redirect) -> redirect + .httpsRedirectWhen((e) -> e.getRequest().getHeaders().containsKey("X-Forwarded-Proto")) ); return http.build(); } diff --git a/docs/modules/ROOT/pages/reactive/integrations/cors.adoc b/docs/modules/ROOT/pages/reactive/integrations/cors.adoc index 84b3a6faf0..125ae4d70f 100644 --- a/docs/modules/ROOT/pages/reactive/integrations/cors.adoc +++ b/docs/modules/ROOT/pages/reactive/integrations/cors.adoc @@ -55,7 +55,7 @@ Java:: SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http // ... - .cors(cors -> cors.disable()); + .cors((cors) -> cors.disable()); return http.build(); } ---- diff --git a/docs/modules/ROOT/pages/reactive/integrations/rsocket.adoc b/docs/modules/ROOT/pages/reactive/integrations/rsocket.adoc index afd07b21be..4046db7103 100644 --- a/docs/modules/ROOT/pages/reactive/integrations/rsocket.adoc +++ b/docs/modules/ROOT/pages/reactive/integrations/rsocket.adoc @@ -426,7 +426,7 @@ rsocket authz .setup().hasRole("SETUP") // <1> .route("fetch.profile.me").authenticated() // <2> - .matcher(payloadExchange -> isMatch(payloadExchange)) // <3> + .matcher((payloadExchange) -> payloadExchange(payloadExchange)) // <3> .hasRole("CUSTOM") .route("fetch.profile.{username}") // <4> .access((authentication, context) -> checkFriends(authentication, context)) diff --git a/docs/modules/ROOT/pages/reactive/oauth2/client/authorization-grants.adoc b/docs/modules/ROOT/pages/reactive/oauth2/client/authorization-grants.adoc index 59def321a4..15ea7789e0 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/client/authorization-grants.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/client/authorization-grants.adoc @@ -145,10 +145,10 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(authorize -> authorize + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .authorizationRequestResolver( authorizationRequestResolver(this.clientRegistrationRepository) ) @@ -170,7 +170,7 @@ public class OAuth2LoginSecurityConfig { private Consumer authorizationRequestCustomizer() { return customizer -> customizer - .additionalParameters(params -> params.put("prompt", "consent")); + .additionalParameters((params) -> params.put("prompt", "consent")); } } ---- @@ -252,7 +252,7 @@ Java:: ---- private Consumer authorizationRequestCustomizer() { return customizer -> customizer - .authorizationRequestUri(uriBuilder -> uriBuilder + .authorizationRequestUri((uriBuilder) -> uriBuilder .queryParam("prompt", "consent").build()); } ---- @@ -301,7 +301,7 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .oauth2Client(oauth2 -> oauth2 + .oauth2Client((oauth2) -> oauth2 .authorizationRequestRepository(this.authorizationRequestRepository()) // ... ); @@ -370,7 +370,7 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .oauth2Client(oauth2 -> oauth2 + .oauth2Client((oauth2) -> oauth2 .authenticationManager(this.authorizationCodeAuthenticationManager()) // ... ); @@ -461,7 +461,7 @@ ReactiveOAuth2AccessTokenResponseClient refreshT ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() - .refreshToken(configurer -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient)) + .refreshToken((configurer) -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient)) .build(); // ... @@ -540,7 +540,7 @@ ReactiveOAuth2AccessTokenResponseClient cli ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder() - .clientCredentials(configurer -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient)) + .clientCredentials((configurer) -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient)) .build(); // ... @@ -748,7 +748,7 @@ ReactiveOAuth2AccessTokenResponseClient passwordToke ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder() - .password(configurer -> configurer.accessTokenResponseClient(passwordTokenResponseClient)) + .password((configurer) -> configurer.accessTokenResponseClient(passwordTokenResponseClient)) .refreshToken() .build(); diff --git a/docs/modules/ROOT/pages/reactive/oauth2/client/index.adoc b/docs/modules/ROOT/pages/reactive/oauth2/client/index.adoc index 52b81363e1..2260f7d5ae 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/client/index.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/client/index.adoc @@ -38,7 +38,7 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .oauth2Client(oauth2 -> oauth2 + .oauth2Client((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository()) .authorizedClientRepository(this.authorizedClientRepository()) .authorizationRequestRepository(this.authorizationRequestRepository()) diff --git a/docs/modules/ROOT/pages/reactive/oauth2/login/advanced.adoc b/docs/modules/ROOT/pages/reactive/oauth2/login/advanced.adoc index 4b6391eeda..1386480e09 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/login/advanced.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/login/advanced.adoc @@ -36,7 +36,7 @@ public class OAuth2LoginSecurityConfig { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .authenticationConverter(this.authenticationConverter()) .authenticationMatcher(this.authenticationMatcher()) .authenticationManager(this.authenticationManager()) @@ -135,10 +135,10 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .exceptionHandling(exceptionHandling -> exceptionHandling + .exceptionHandling((exceptionHandling) -> exceptionHandling .authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/login/oauth2")) ) - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .authorizationRequestResolver(this.authorizationRequestResolver()) ); @@ -239,7 +239,7 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .authenticationMatcher(new PathPatternParserServerWebExchangeMatcher("/login/oauth2/callback/{registrationId}")) ); @@ -688,7 +688,7 @@ Java:: @Bean public ReactiveJwtDecoderFactory idTokenDecoderFactory() { ReactiveOidcIdTokenDecoderFactory idTokenDecoderFactory = new ReactiveOidcIdTokenDecoderFactory(); - idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256); + idTokenDecoderFactory.setJwsAlgorithmResolver((clientRegistration) -> clientRegistration.HS256); return idTokenDecoderFactory; } ---- diff --git a/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc b/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc index a98676f846..c08a60e078 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/login/core.adoc @@ -337,7 +337,7 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(authorize -> authorize + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2Login(withDefaults()); @@ -390,7 +390,7 @@ public class OAuth2LoginConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(authorize -> authorize + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2Login(withDefaults()); @@ -487,7 +487,7 @@ public class OAuth2LoginConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(authorize -> authorize + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2Login(withDefaults()); diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/bearer-tokens.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/bearer-tokens.adoc index 7fd0b4cc04..496f5d9108 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/bearer-tokens.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/bearer-tokens.adoc @@ -19,7 +19,7 @@ Java:: ServerBearerTokenAuthenticationConverter converter = new ServerBearerTokenAuthenticationConverter(); converter.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION); http - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .bearerTokenConverter(converter) ); ---- @@ -108,7 +108,7 @@ Java:: ---- this.rest.get() .uri("https://other-service.example.com/endpoint") - .headers(headers -> headers.setBearerAuth(overridingToken)) + .headers((headers) -> headers.setBearerAuth(overridingToken)) .retrieve() .bodyToMono(String.class) ---- diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc index bc9d827f22..0d404deb79 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc @@ -128,7 +128,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerSpec::jwt) @@ -170,11 +170,11 @@ import static org.springframework.security.oauth2.core.authorization.OAuth2React @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .pathMatchers("/message/**").access(hasScope("message:read")) .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .jwt(withDefaults()) ); return http.build(); @@ -254,11 +254,11 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwkSetUri("https://idp.example.com/.well-known/jwks.json") ) ); @@ -302,11 +302,11 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .decoder(myCustomDecoder()) ) ); @@ -691,7 +691,7 @@ import static org.springframework.security.oauth2.core.authorization.OAuth2React @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .mvcMatchers("/contacts/**").access(hasScope("contacts")) .mvcMatchers("/messages/**").access(hasScope("messages")) .anyExchange().authenticated() @@ -762,11 +762,11 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwtAuthenticationConverter(grantedAuthoritiesExtractor()) ) ); diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc index 7dd3c6b5a1..b1353c8cf9 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc @@ -27,10 +27,10 @@ JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = J .fromTrustedIssuers("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo"); http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .authenticationManagerResolver(authenticationManagerResolver) ); ---- @@ -74,7 +74,7 @@ private Mono addManager( return Mono.fromCallable(() -> ReactiveJwtDecoders.fromIssuerLocation(issuer)) .subscribeOn(Schedulers.boundedElastic()) .map(JwtReactiveAuthenticationManager::new) - .doOnNext(authenticationManager -> authenticationManagers.put(issuer, authenticationManager)); + .doOnNext((authenticationManager) -> authenticationManager.put(issuer, authenticationManager)); } // ... @@ -83,10 +83,10 @@ JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get); http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .authenticationManagerResolver(authenticationManagerResolver) ); ---- diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc index 57496f2ebb..1293acf8ae 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc @@ -176,7 +176,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) .oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::opaqueToken) @@ -221,12 +221,12 @@ public class MyCustomSecurityConfiguration { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .pathMatchers("/messages/**").access(hasScope("message:read")) .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspector(myIntrospector()) ) ); @@ -310,11 +310,11 @@ public class DirectlyConfiguredIntrospectionUri { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspectionUri("https://idp.example.com/introspect") .introspectionClientCredentials("client", "secret") ) @@ -364,11 +364,11 @@ public class DirectlyConfiguredIntrospector { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspector(myCustomIntrospector()) ) ); @@ -457,7 +457,7 @@ public class MappedAuthorities { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange(exchange -> exchange + .authorizeExchange((exchange) -> exchange .pathMatchers("/contacts/**").access(hasScope("contacts")) .pathMatchers("/messages/**").access(hasScope("messages")) .anyExchange().authenticated() @@ -543,7 +543,7 @@ public class CustomAuthoritiesOpaqueTokenIntrospector implements ReactiveOpaqueT public Mono introspect(String token) { return this.delegate.introspect(token) - .map(principal -> new DefaultOAuth2AuthenticatedPrincipal( + .map((principal) -> principal DefaultOAuth2AuthenticatedPrincipal( principal.getName(), principal.getAttributes(), extractAuthorities(principal))); } @@ -650,8 +650,8 @@ public class JwtOpaqueTokenIntrospector implements ReactiveOpaqueTokenIntrospect public Mono introspect(String token) { return this.delegate.introspect(token) - .flatMap(principal -> this.jwtDecoder.decode(token)) - .map(jwt -> new DefaultOAuth2AuthenticatedPrincipal(jwt.getClaims(), NO_AUTHORITIES)); + .flatMap((principal) -> principal.jwtDecoder.decode(token)) + .map((jwt) -> jwt DefaultOAuth2AuthenticatedPrincipal(jwt.getClaims(), NO_AUTHORITIES)); } private static class ParseOnlyJWTProcessor implements Converter> { diff --git a/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc b/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc index 2548d96cf5..c37d85e189 100644 --- a/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc +++ b/docs/modules/ROOT/pages/reactive/test/web/oauth2.adoc @@ -227,7 +227,7 @@ Java:: ---- client .mutateWith(mockOidcLogin() - .idToken(token -> token.claim("user_id", "1234")) + .idToken((token) -> token.claim("user_id", "1234")) ) .get().uri("/endpoint").exchange(); ---- @@ -470,7 +470,7 @@ Java:: ---- client .mutateWith(mockOAuth2Login() - .attributes(attrs -> attrs.put("user_id", "1234")) + .attributes((attrs) -> attrs.put("user_id", "1234")) ) .get().uri("/endpoint").exchange(); ---- @@ -869,7 +869,7 @@ Java:: [source,java,role="primary"] ---- client - .mutateWith(mockJwt().jwt(jwt -> jwt.header("kid", "one") + .mutateWith(mockJwt().jwt((jwt) -> jwt.header("kid", "one") .claim("iss", "https://idp.example.org"))) .get().uri("/endpoint").exchange(); ---- @@ -893,7 +893,7 @@ Java:: [source,java,role="primary"] ---- client - .mutateWith(mockJwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))) + .mutateWith(mockJwt().jwt((jwt) -> jwt.claims((claims) -> claims.remove("scope")))) .get().uri("/endpoint").exchange(); ---- @@ -1206,7 +1206,7 @@ Java:: ---- client .mutateWith(mockOpaqueToken() - .attributes(attrs -> attrs.put("user_id", "1234")) + .attributes((attrs) -> attrs.put("user_id", "1234")) ) .get().uri("/endpoint").exchange(); ---- diff --git a/docs/modules/ROOT/pages/servlet/architecture.adoc b/docs/modules/ROOT/pages/servlet/architecture.adoc index 7bba33945d..bba7f2357c 100644 --- a/docs/modules/ROOT/pages/servlet/architecture.adoc +++ b/docs/modules/ROOT/pages/servlet/architecture.adoc @@ -171,7 +171,7 @@ public class SecurityConfig { .csrf(Customizer.withDefaults()) .httpBasic(Customizer.withDefaults()) .formLogin(Customizer.withDefaults()) - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ); diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/digest.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/digest.adoc index e4af5ebeaf..0beb794cf0 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/passwords/digest.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/digest.adoc @@ -64,7 +64,7 @@ DigestAuthenticationFilter digestAuthenticationFilter() { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .exceptionHandling(e -> e.authenticationEntryPoint(authenticationEntryPoint())) + .exceptionHandling((e) -> e.authenticationEntryPoint(authenticationEntryPoint())) .addFilter(digestAuthenticationFilter()); return http.build(); } diff --git a/docs/modules/ROOT/pages/servlet/authentication/passwords/form.adoc b/docs/modules/ROOT/pages/servlet/authentication/passwords/form.adoc index bead43bdcc..afb1c30046 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/passwords/form.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/passwords/form.adoc @@ -120,7 +120,7 @@ Java:: ---- public SecurityFilterChain filterChain(HttpSecurity http) { http - .formLogin(form -> form + .formLogin((form) -> form .loginPage("/login") .permitAll() ); diff --git a/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc b/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc index 0eb0f05f0d..1022e738c2 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/session-management.adoc @@ -359,7 +359,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .sessionManagement(session -> session + .sessionManagement((session) -> session .maximumSessions(1) ); return http.build(); @@ -412,7 +412,7 @@ Java:: public SecurityFilterChain filterChain(HttpSecurity http) { AuthorizationManager isAdmin = AuthorityAuthorizationManager.hasRole("ADMIN"); http - .sessionManagement(session -> session + .sessionManagement((session) -> session .maximumSessions((authentication) -> isAdmin.authorize(() -> authentication, null).isGranted() ? -1 : 1) ); return http.build(); @@ -504,7 +504,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .sessionManagement(session -> session + .sessionManagement((session) -> session .maximumSessions(1) .maxSessionsPreventsLogin(true) ); @@ -612,7 +612,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .sessionManagement(session -> session + .sessionManagement((session) -> session .invalidSessionUrl("/invalidSession") ); return http.build(); @@ -663,7 +663,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .sessionManagement(session -> session + .sessionManagement((session) -> session .invalidSessionStrategy(new MyCustomInvalidSessionStrategy()) ); return http.build(); @@ -767,7 +767,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .logout(logout -> logout + .logout((logout) -> logout .deleteCookies("JSESSIONID") ); return http.build(); @@ -971,7 +971,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) { http - .sessionManagement(session -> session + .sessionManagement((session) -> session .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) ); return http.build(); diff --git a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc index ca3fd6b2bf..2d435ff36c 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc @@ -741,7 +741,7 @@ import static org.springframework.security.authorization.AuthorityAuthorizationM SecurityFilterChain web(HttpSecurity http) throws Exception { http // ... - .authorizeHttpRequests(authorize -> authorize // <1> + .authorizeHttpRequests((authorize) -> authorize // <1> .dispatcherTypeMatchers(FORWARD, ERROR).permitAll() // <2> .requestMatchers("/static/**", "/signup", "/about").permitAll() // <3> .requestMatchers("/admin/**").hasRole("ADMIN") // <4> @@ -1043,7 +1043,7 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/api/**") <1> - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/api/user/**").hasRole("USER") <2> .requestMatchers("/api/admin/**").hasRole("ADMIN") <3> .anyRequest().authenticated() <4> @@ -1106,7 +1106,7 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher(antMatcher("/api/**")) <2> - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers(antMatcher("/api/user/**")).hasRole("USER") <3> .requestMatchers(regexMatcher("/api/admin/.*")).hasRole("ADMIN") <4> .requestMatchers(new MyCustomRequestMatcher()).hasRole("SUPERVISOR") <5> diff --git a/docs/modules/ROOT/pages/servlet/configuration/java.adoc b/docs/modules/ROOT/pages/servlet/configuration/java.adoc index f72abe73d7..a3c09f5732 100644 --- a/docs/modules/ROOT/pages/servlet/configuration/java.adoc +++ b/docs/modules/ROOT/pages/servlet/configuration/java.adoc @@ -173,7 +173,7 @@ It is configured with the following default implementation: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) @@ -228,7 +228,7 @@ public class MultiHttpSecurityConfig { public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/api/**") <3> - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasRole("ADMIN") ) .httpBasic(Customizer.withDefaults()); @@ -238,7 +238,7 @@ public class MultiHttpSecurityConfig { @Bean <4> public SecurityFilterChain formLoginFilterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()); @@ -297,7 +297,7 @@ public class PartialSecurityConfig { public SecurityFilterChain securedFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/secured/**") <1> - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/secured/user").hasRole("USER") <2> .requestMatchers("/secured/admin").hasRole("ADMIN") <3> .anyRequest().authenticated() <4> @@ -357,15 +357,15 @@ public class SecuredSecurityConfig { public SecurityFilterChain securedFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/secured/**") <1> - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() <2> ) - .formLogin(formLogin -> formLogin <3> + .formLogin((formLogin) -> formLogin <3> .loginPage("/secured/login") .loginProcessingUrl("/secured/login") .permitAll() ) - .logout(logout -> logout <4> + .logout((logout) -> logout <4> .logoutUrl("/secured/logout") .logoutSuccessUrl("/secured/login?logout") .permitAll() @@ -377,7 +377,7 @@ public class SecuredSecurityConfig { @Bean public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll() <5> ); return http.build(); @@ -424,7 +424,7 @@ public class BankingSecurityConfig { String[] approvalsPaths = { "/accounts/approvals/**", "/loans/approvals/**", "/credit-cards/approvals/**" }; http .securityMatcher(approvalsPaths) - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasRole("ADMIN") ) .httpBasic(Customizer.withDefaults()); @@ -438,7 +438,7 @@ public class BankingSecurityConfig { String[] viewBalancePaths = { "/balances/**" }; http .securityMatcher(bankingPaths) - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers(viewBalancePaths).hasRole("VIEW_BALANCE") .anyRequest().hasRole("USER") ); @@ -449,15 +449,15 @@ public class BankingSecurityConfig { public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { String[] allowedPaths = { "/", "/user-login", "/user-logout", "/notices", "/contact", "/register" }; http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers(allowedPaths).permitAll() .anyRequest().authenticated() ) - .formLogin(formLogin -> formLogin + .formLogin((formLogin) -> formLogin .loginPage("/user-login") .loginProcessingUrl("/user-login") ) - .logout(logout -> logout + .logout((logout) -> logout .logoutUrl("/user-logout") .logoutSuccessUrl("/?logout") ); @@ -680,7 +680,7 @@ For example, to configure the `filterSecurityPublishAuthorizationSuccess` proper @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() .withObjectPostProcessor(new ObjectPostProcessor() { public O postProcess( diff --git a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc index ac3f341ac1..5b12c92f74 100644 --- a/docs/modules/ROOT/pages/servlet/exploits/headers.adoc +++ b/docs/modules/ROOT/pages/servlet/exploits/headers.adoc @@ -30,8 +30,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions .sameOrigin() ) ); @@ -96,7 +96,7 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers + .headers((headers) -> headers // do not use any default headers unless explicitly listed .defaultsDisabled() .cacheControl(withDefaults()) @@ -160,7 +160,7 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers.disable()); + .headers((headers) -> headers.disable()); return http.build(); } } @@ -226,8 +226,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .cacheControl(cache -> cache.disable()) + .headers((headers) -> headers + .cacheControl((cache) -> cache.disable()) ); return http.build(); } @@ -291,8 +291,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable()) + .headers((headers) -> headers + .contentTypeOptions((contentTypeOptions) -> contentTypeOptions.disable()) ); return http.build(); } @@ -357,8 +357,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .httpStrictTransportSecurity(hsts -> hsts + .headers((headers) -> headers + .httpStrictTransportSecurity((hsts) -> hsts .includeSubDomains(true) .preload(true) .maxAgeInSeconds(31536000) @@ -431,8 +431,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .httpPublicKeyPinning(hpkp -> hpkp + .headers((headers) -> headers + .httpPublicKeyPinning((hpkp) -> hpkp .includeSubDomains(true) .reportUri("https://example.net/pkp-report") .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=") @@ -511,8 +511,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions .sameOrigin() ) ); @@ -582,8 +582,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .xssProtection(xss -> xss + .headers((headers) -> headers + .xssProtection((xss) -> xss .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) ) ); @@ -660,8 +660,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .contentSecurityPolicy(csp -> csp + .headers((headers) -> headers + .contentSecurityPolicy((csp) -> csp .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") ) ); @@ -725,8 +725,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .contentSecurityPolicy(csp -> csp + .headers((headers) -> headers + .contentSecurityPolicy((csp) -> csp .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/") .reportOnly() ) @@ -797,8 +797,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .referrerPolicy(referrer -> referrer + .headers((headers) -> headers + .referrerPolicy((referrer) -> referrer .policy(ReferrerPolicy.SAME_ORIGIN) ) ); @@ -873,7 +873,7 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers + .headers((headers) -> headers .featurePolicy("geolocation 'self'") ); return http.build(); @@ -945,8 +945,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .permissionsPolicy(permissions -> permissions + .headers((headers) -> headers + .permissionsPolicy((permissions) -> permissions .policy("geolocation=(self)") ) ); @@ -1082,7 +1082,7 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers + .headers((headers) -> headers .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value")) ); return http.build(); @@ -1147,7 +1147,7 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers + .headers((headers) -> headers .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)) ); return http.build(); @@ -1223,8 +1223,8 @@ public class WebSecurityConfig { new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter()); http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions.disable()) + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions.disable()) .addHeaderWriter(headerWriter) ); return http.build(); diff --git a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc index 9513600dd2..736e5b15f4 100644 --- a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc +++ b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc @@ -440,7 +440,7 @@ public class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer private final ApplicationContext applicationContext; private final AuthorizationManager> authorizationManager; - + public WebSocketSecurityConfig(ApplicationContext applicationContext, AuthorizationManager> authorizationManager) { this.applicationContext = applicationContext; this.authorizationManager = authorizationManager; @@ -607,8 +607,8 @@ public class WebSecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... - .headers(headers -> headers - .frameOptions(frameOptions -> frameOptions + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions .sameOrigin() ) ); @@ -670,17 +670,17 @@ public class WebSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .csrf(csrf -> csrf + .csrf((csrf) -> csrf // ignore our stomp endpoints since they are protected using Stomp headers .ignoringRequestMatchers("/chat/**") ) - .headers(headers -> headers + .headers((headers) -> headers // allow same origin to frame our site to support iframe SockJS - .frameOptions(frameOptions -> frameOptions + .frameOptions((frameOptions) -> frameOptions .sameOrigin() ) ) - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize ... ) ... diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc index f2f14be45e..ce0323c123 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc @@ -147,11 +147,11 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2Login(oauth2 -> oauth2 - .authorizationEndpoint(authorization -> authorization + .oauth2Login((oauth2) -> oauth2 + .authorizationEndpoint((authorization) -> authorization .authorizationRequestResolver( authorizationRequestResolver(this.clientRegistrationRepository) ) @@ -174,7 +174,7 @@ public class OAuth2LoginSecurityConfig { private Consumer authorizationRequestCustomizer() { return customizer -> customizer - .additionalParameters(params -> params.put("prompt", "consent")); + .additionalParameters((params) -> params.put("prompt", "consent")); } } ---- @@ -257,7 +257,7 @@ Java:: ---- private Consumer authorizationRequestCustomizer() { return customizer -> customizer - .authorizationRequestUri(uriBuilder -> uriBuilder + .authorizationRequestUri((uriBuilder) -> uriBuilder .queryParam("prompt", "consent").build()); } ---- @@ -306,14 +306,14 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Client(oauth2 -> oauth2 - .authorizationCodeGrant(codeGrant -> codeGrant + .oauth2Client((oauth2) -> oauth2 + .authorizationCodeGrant((codeGrant) -> codeGrant .authorizationRequestRepository(this.authorizationRequestRepository()) // ... ) ) - .oauth2Login(oauth2 -> oauth2 - .authorizationEndpoint(endpoint -> endpoint + .oauth2Login((oauth2) -> oauth2 + .authorizationEndpoint((endpoint) -> endpoint .authorizationRequestRepository(this.authorizationRequestRepository()) // ... ) @@ -412,8 +412,8 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Client(oauth2 -> oauth2 - .authorizationCodeGrant(codeGrant -> codeGrant + .oauth2Client((oauth2) -> oauth2 + .authorizationCodeGrant((codeGrant) -> codeGrant .accessTokenResponseClient(this.accessTokenResponseClient()) // ... ) @@ -514,7 +514,7 @@ OAuth2AccessTokenResponseClient refreshTokenToke OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() - .refreshToken(configurer -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient)) + .refreshToken((configurer) -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient)) .build(); // ... @@ -605,7 +605,7 @@ OAuth2AccessTokenResponseClient clientCrede OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() - .clientCredentials(configurer -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient)) + .clientCredentials((configurer) -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient)) .build(); // ... @@ -882,7 +882,7 @@ OAuth2AccessTokenResponseClient passwordTokenRespons OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() - .password(configurer -> configurer.accessTokenResponseClient(passwordTokenResponseClient)) + .password((configurer) -> configurer.accessTokenResponseClient(passwordTokenResponseClient)) .refreshToken() .build(); diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc index bec08cf2ef..3ef66f0fef 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc @@ -40,11 +40,11 @@ public class OAuth2ClientSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Client(oauth2 -> oauth2 + .oauth2Client((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository()) .authorizedClientRepository(this.authorizedClientRepository()) .authorizedClientService(this.authorizedClientService()) - .authorizationCodeGrant(codeGrant -> codeGrant + .authorizationCodeGrant((codeGrant) -> codeGrant .authorizationRequestRepository(this.authorizationRequestRepository()) .authorizationRequestResolver(this.authorizationRequestResolver()) .accessTokenResponseClient(this.accessTokenResponseClient()) diff --git a/docs/modules/ROOT/pages/servlet/oauth2/login/advanced.adoc b/docs/modules/ROOT/pages/servlet/oauth2/login/advanced.adoc index 53c9381026..2162be9d28 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/login/advanced.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/login/advanced.adoc @@ -22,17 +22,17 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .authorizationEndpoint(authorization -> authorization + .oauth2Login((oauth2) -> oauth2 + .authorizationEndpoint((authorization) -> authorization ... ) - .redirectionEndpoint(redirection -> redirection + .redirectionEndpoint((redirection) -> redirection ... ) - .tokenEndpoint(token -> token + .tokenEndpoint((token) -> token ... ) - .userInfoEndpoint(userInfo -> userInfo + .userInfoEndpoint((userInfo) -> userInfo ... ) ); @@ -108,23 +108,23 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository()) .authorizedClientRepository(this.authorizedClientRepository()) .authorizedClientService(this.authorizedClientService()) .loginPage("/login") - .authorizationEndpoint(authorization -> authorization + .authorizationEndpoint((authorization) -> authorization .baseUri(this.authorizationRequestBaseUri()) .authorizationRequestRepository(this.authorizationRequestRepository()) .authorizationRequestResolver(this.authorizationRequestResolver()) ) - .redirectionEndpoint(redirection -> redirection + .redirectionEndpoint((redirection) -> redirection .baseUri(this.authorizationResponseBaseUri()) ) - .tokenEndpoint(token -> token + .tokenEndpoint((token) -> token .accessTokenResponseClient(this.accessTokenResponseClient()) ) - .userInfoEndpoint(userInfo -> userInfo + .userInfoEndpoint((userInfo) -> userInfo .userAuthoritiesMapper(this.userAuthoritiesMapper()) .userService(this.oauth2UserService()) .oidcUserService(this.oidcUserService()) @@ -250,10 +250,10 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 + .oauth2Login((oauth2) -> oauth2 .loginPage("/login/oauth2") ... - .authorizationEndpoint(authorization -> authorization + .authorizationEndpoint((authorization) -> authorization .baseUri("/login/oauth2/authorization") ... ) @@ -345,8 +345,8 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .redirectionEndpoint(redirection -> redirection + .oauth2Login((oauth2) -> oauth2 + .redirectionEndpoint((redirection) -> redirection .baseUri("/login/oauth2/callback/*") ... ) @@ -469,8 +469,8 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .userInfoEndpoint(userInfo -> userInfo + .oauth2Login((oauth2) -> oauth2 + .userInfoEndpoint((userInfo) -> userInfo .userAuthoritiesMapper(this.userAuthoritiesMapper()) ... ) @@ -636,8 +636,8 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .userInfoEndpoint(userInfo -> userInfo + .oauth2Login((oauth2) -> oauth2 + .userInfoEndpoint((userInfo) -> userInfo .oidcUserService(this.oidcUserService()) ... ) @@ -776,8 +776,8 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .userInfoEndpoint(userInfo -> userInfo + .oauth2Login((oauth2) -> oauth2 + .userInfoEndpoint((userInfo) -> userInfo .userService(this.oauth2UserService()) ... ) @@ -844,8 +844,8 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .oauth2Login(oauth2 -> oauth2 - .userInfoEndpoint(userInfo -> userInfo + .oauth2Login((oauth2) -> oauth2 + .userInfoEndpoint((userInfo) -> userInfo .oidcUserService(this.oidcUserService()) ... ) @@ -911,7 +911,7 @@ Java:: @Bean public JwtDecoderFactory idTokenDecoderFactory() { OidcIdTokenDecoderFactory idTokenDecoderFactory = new OidcIdTokenDecoderFactory(); - idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256); + idTokenDecoderFactory.setJwsAlgorithmResolver((clientRegistration) -> clientRegistration.HS256); return idTokenDecoderFactory; } ---- diff --git a/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc b/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc index 4c179cc62a..b77ca2ce66 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/login/core.adoc @@ -332,7 +332,7 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2Login(withDefaults()); @@ -381,7 +381,7 @@ public class OAuth2LoginConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2Login(withDefaults()); @@ -475,7 +475,7 @@ public class OAuth2LoginConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2Login(withDefaults()); diff --git a/docs/modules/ROOT/pages/servlet/oauth2/login/logout.adoc b/docs/modules/ROOT/pages/servlet/oauth2/login/logout.adoc index 4230cd2c24..2b0190bf31 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/login/logout.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/login/logout.adoc @@ -57,11 +57,11 @@ public class OAuth2LoginSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2Login(withDefaults()) - .logout(logout -> logout + .logout((logout) -> logout .logoutSuccessHandler(oidcLogoutSuccessHandler()) ); return http.build(); diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/bearer-tokens.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/bearer-tokens.adoc index aea9d358fc..c9e47f14a2 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/bearer-tokens.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/bearer-tokens.adoc @@ -69,7 +69,7 @@ Java:: DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver(); resolver.setAllowFormEncodedBodyParameter(true); http - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .bearerTokenResolver(resolver) ); ---- @@ -176,7 +176,7 @@ Java:: ---- this.rest.get() .uri("https://other-service.example.com/endpoint") - .headers(headers -> headers.setBearerAuth(overridingToken)) + .headers((headers) -> headers.setBearerAuth(overridingToken)) .retrieve() .bodyToMono(String.class) .block() diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/jwt.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/jwt.adoc index d5e10dbf83..56fd683ec9 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/jwt.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/jwt.adoc @@ -174,7 +174,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults())); @@ -220,12 +220,12 @@ public class MyCustomSecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/messages/**").access(hasScope("message:read")) .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwtAuthenticationConverter(myConverter()) ) ); @@ -355,11 +355,11 @@ public class DirectlyConfiguredJwkSetUri { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwkSetUri("https://idp.example.com/.well-known/jwks.json") ) ); @@ -425,11 +425,11 @@ public class DirectlyConfiguredJwtDecoder { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .decoder(myCustomDecoder()) ) ); @@ -875,12 +875,12 @@ public class DirectlyConfiguredJwkSetUri { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/contacts/**").access(hasScope("contacts")) .requestMatchers("/messages/**").access(hasScope("messages")) .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .jwt(Customizer.withDefaults()) ); return http.build(); @@ -1107,11 +1107,11 @@ public class CustomAuthenticationConverterConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwtAuthenticationConverter(new CustomAuthenticationConverter()) ) ); diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/multitenancy.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/multitenancy.adoc index 8b1aec78e2..3dd75fe2ed 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/multitenancy.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/multitenancy.adoc @@ -58,10 +58,10 @@ Java:: [source,java,role="primary"] ---- http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .authenticationManagerResolver(this.tokenAuthenticationManagerResolver) ); ---- @@ -118,10 +118,10 @@ JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = JwtIssuer .fromTrustedIssuers("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo"); http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .authenticationManagerResolver(authenticationManagerResolver) ); ---- @@ -189,10 +189,10 @@ JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get); http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .authenticationManagerResolver(authenticationManagerResolver) ); ---- @@ -265,7 +265,7 @@ public class TenantJWSKeySelector private JWSKeySelector fromTenant(String tenant) { return Optional.ofNullable(this.tenants.findById(tenant)) <3> - .map(t -> t.getAttrbute("jwks_uri")) + .map((t) -> t.getAttrbute("jwks_uri")) .map(this::fromUri) .orElseThrow(() -> new IllegalArgumentException("unknown tenant")); } diff --git a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc index a143fe423b..c8df5b4b52 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/servlet/oauth2/resource-server/opaque-token.adoc @@ -201,10 +201,10 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .opaqueToken(Customizer.withDefaults()) ); return http.build(); @@ -249,12 +249,12 @@ public class MyCustomSecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/messages/**").access(hasScope("message:read")) .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspector(myIntrospector()) ) ); @@ -400,11 +400,11 @@ public class DirectlyConfiguredIntrospectionUri { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspectionUri("https://idp.example.com/introspect") .introspectionClientCredentials("client", "secret") ) @@ -472,11 +472,11 @@ public class DirectlyConfiguredIntrospector { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 - .opaqueToken(opaqueToken -> opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspector(myCustomIntrospector()) ) ); @@ -564,12 +564,12 @@ public class MappedAuthorities { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorizeRequests -> authorizeRequests + .authorizeHttpRequests((authorizeRequests) -> authorizeRequests .requestMatchers("/contacts/**").access(hasScope("contacts")) .requestMatchers("/messages/**").access(hasScope("messages")) .anyRequest().authenticated() ) - .oauth2ResourceServer(oauth2 -> oauth2 + .oauth2ResourceServer((oauth2) -> oauth2 .opaqueToken(Customizer.withDefaults()) ); return http.build(); diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc index 4558b7a4ec..ccce691c04 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication-requests.adoc @@ -156,7 +156,7 @@ Java:: ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta") // ... - .assertingPartyMetadata(party -> party + .assertingPartyMetadata((party) -> party // ... .wantAuthnRequestsSigned(false) ) @@ -239,7 +239,7 @@ Java:: ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta") // ... - .assertingPartyMetadata(party -> party + .assertingPartyMetadata((party) -> party // ... .singleSignOnServiceBinding(Saml2MessageBinding.POST) ) diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index 400a66ad3a..cf794fe100 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -148,10 +148,10 @@ public class SecurityConfig { ); http - .authorizeHttpRequests(authz -> authz + .authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) - .saml2Login(saml2 -> saml2 + .saml2Login((saml2) -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ); return http.build(); @@ -211,10 +211,10 @@ public class SecurityConfig { .clockSkew(Duration.ofMinutes(10)).build(); authenticationProvider.setAssertionValidator(assertionValidator); http - .authorizeHttpRequests(authz -> authz + .authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) - .saml2Login(saml2 -> saml2 + .saml2Login((saml2) -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ); return http.build(); @@ -409,10 +409,10 @@ public class SecurityConfig { }); http - .authorizeHttpRequests(authz -> authz + .authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) - .saml2Login(saml2 -> saml2 + .saml2Login((saml2) -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ); return http.build(); @@ -780,10 +780,10 @@ public class SecurityConfig { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { AuthenticationManager authenticationManager = new MySaml2AuthenticationManager(...); http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .saml2Login(saml2 -> saml2 + .saml2Login((saml2) -> saml2 .authenticationManager(authenticationManager) ) ; diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc index a67244d05b..7356b74fce 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc @@ -342,7 +342,7 @@ Java:: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .saml2Login(withDefaults()); @@ -384,7 +384,7 @@ public class MyCustomSecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/messages/**").hasAuthority("ROLE_USER") .anyRequest().authenticated() ) @@ -486,11 +486,11 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc Saml2X509Credential credential = Saml2X509Credential.verification(certificate); RelyingPartyRegistration registration = RelyingPartyRegistration .withRegistrationId("example") - .assertingPartyMetadata(party -> party + .assertingPartyMetadata((party) -> party .entityId("https://idp.example.com/issuer") .singleSignOnServiceLocation("https://idp.example.com/SSO.saml2") .wantAuthnRequestsSigned(false) - .verificationX509Credentials(c -> c.add(credential)) + .verificationX509Credentials((c) -> c.add(credential)) ) .build(); return new InMemoryRelyingPartyRegistrationRepository(registration); @@ -549,11 +549,11 @@ public class MyCustomSecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(authorize -> authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/messages/**").hasAuthority("ROLE_USER") .anyRequest().authenticated() ) - .saml2Login(saml2 -> saml2 + .saml2Login((saml2) -> saml2 .relyingPartyRegistrationRepository(relyingPartyRegistrations()) ); return http.build(); @@ -699,11 +699,11 @@ Java:: ---- RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("my-id") .entityId("{baseUrl}/{registrationId}") - .decryptionX509Credentials(c -> c.add(relyingPartyDecryptingCredential())) + .decryptionX509Credentials((c) -> c.add(relyingPartyDecryptingCredential())) .assertionConsumerServiceLocation("/my-login-endpoint/{registrationId}") - .assertingPartyMetadata(party -> party + .assertingPartyMetadata((party) -> party .entityId("https://ap.example.org") - .verificationX509Credentials(c -> c.add(assertingPartyVerifyingCredential())) + .verificationX509Credentials((c) -> c.add(assertingPartyVerifyingCredential())) .singleSignOnServiceLocation("https://ap.example.org/SSO.saml2") ) .build(); @@ -913,7 +913,7 @@ private RelyingPartyRegistration.Builder addRelyingPartyDetails(RelyingPartyRegistration.Builder builder) { Saml2X509Credential signingCredential = ... - builder.signingX509Credentials(c -> c.addAll(signingCredential)); + builder.signingX509Credentials((c) -> c.addAll(signingCredential)); // ... other relying party configurations } diff --git a/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc b/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc index 581f49adef..8c4db2fb0b 100644 --- a/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc +++ b/docs/modules/ROOT/pages/servlet/test/mockmvc/oauth2.adoc @@ -228,7 +228,7 @@ Java:: mvc .perform(get("/endpoint") .with(oidcLogin() - .idToken(token -> token.claim("user_id", "1234")) + .idToken((token) -> token.claim("user_id", "1234")) ) ); ---- @@ -475,7 +475,7 @@ Java:: mvc .perform(get("/endpoint") .with(oauth2Login() - .attributes(attrs -> attrs.put("user_id", "1234")) + .attributes((attrs) -> attrs.put("user_id", "1234")) ) ); ---- @@ -875,7 +875,7 @@ Java:: ---- mvc .perform(get("/endpoint") - .with(jwt().jwt(jwt -> jwt.header("kid", "one").claim("iss", "https://idp.example.org")))); + .with(jwt().jwt((jwt) -> jwt.header("kid", "one").claim("iss", "https://idp.example.org")))); ---- Kotlin:: @@ -898,7 +898,7 @@ Java:: ---- mvc .perform(get("/endpoint") - .with(jwt().jwt(jwt -> jwt.claims(claims -> claims.remove("scope"))))); + .with(jwt().jwt((jwt) -> jwt.claims((claims) -> claims.remove("scope"))))); ---- Kotlin:: @@ -1219,7 +1219,7 @@ Java:: mvc .perform(get("/endpoint") .with(opaqueToken() - .attributes(attrs -> attrs.put("user_id", "1234")) + .attributes((attrs) -> attrs.put("user_id", "1234")) ) ); ---- diff --git a/docs/modules/ROOT/partials/reactive/oauth2/client/web-client-access-token-response-client.adoc b/docs/modules/ROOT/partials/reactive/oauth2/client/web-client-access-token-response-client.adoc index 49c28aa603..2de8bae3ff 100644 --- a/docs/modules/ROOT/partials/reactive/oauth2/client/web-client-access-token-response-client.adoc +++ b/docs/modules/ROOT/partials/reactive/oauth2/client/web-client-access-token-response-client.adoc @@ -270,7 +270,7 @@ BodyExtractor>, ReactiveHttpInputMessage> bodyExtractor BodyExtractors.toMono(new ParameterizedTypeReference<>() {}); accessTokenResponseClient.setBodyExtractor((inputMessage, context) -> bodyExtractor.extract(inputMessage, context) - .map(parameters -> OAuth2AccessTokenResponse.withToken("custom-token") + .map((parameters) -> parameters.withToken("custom-token") // ... .build() ) diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java index 8f7f8c8278..45679a2ab9 100644 --- a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java @@ -59,11 +59,11 @@ public class CustomX509Configuration { // @formatter:off http - .x509(x509 -> x509 + .x509((x509) -> x509 .principalExtractor(principalExtractor) .authenticationManager(authenticationManager) ) - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ); // @formatter:on diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java index 0fd17fa1d8..ea0f34ddc3 100644 --- a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java @@ -44,7 +44,7 @@ public class DefaultX509Configuration { // @formatter:off http .x509(Customizer.withDefaults()) - .authorizeExchange(exchanges -> exchanges + .authorizeExchange((exchanges) -> exchanges .anyExchange().authenticated() ); // @formatter:on diff --git a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java index a347235386..12f02ad2f1 100644 --- a/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java +++ b/docs/src/test/java/org/springframework/security/docs/servlet/authentication/servletx509config/DefaultX509Configuration.java @@ -44,7 +44,7 @@ public class DefaultX509Configuration { // @formatter:off http .x509(Customizer.withDefaults()) - .authorizeHttpRequests(exchanges -> exchanges + .authorizeHttpRequests((exchanges) -> exchanges .anyRequest().authenticated() ); // @formatter:on From 13e738e73323660efadf1e4ac94bdf7bbd725229 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:05:25 -0600 Subject: [PATCH 399/504] Use HttpSecurity Lambda DSL in Test Issue gh-13067 --- .../test/web/servlet/request/Sec2935Tests.java | 8 ++++---- ...PostProcessorsAuthenticationStatelessTests.java | 4 ++-- ...cRequestPostProcessorsCsrfDebugFilterTests.java | 2 +- ...kMvcRequestPostProcessorsOAuth2ClientTests.java | 5 +++-- ...ckMvcRequestPostProcessorsOAuth2LoginTests.java | 7 ++++--- ...MockMvcRequestPostProcessorsOidcLoginTests.java | 8 ++++---- ...ckMvcRequestPostProcessorsOpaqueTokenTests.java | 11 +++++------ ...rocessorsTestSecurityContextStatelessTests.java | 4 ++-- .../test/web/servlet/response/Gh3409Tests.java | 10 +++++----- .../showcase/csrf/CustomCsrfShowcaseTests.java | 4 ++-- .../login/CustomConfigAuthenticationTests.java | 14 ++++++-------- ...stomLoginRequestBuilderAuthenticationTests.java | 9 ++++----- .../secured/DefaultfSecurityRequestsTests.java | 8 ++++---- .../showcase/secured/SecurityRequestsTests.java | 8 ++++---- .../secured/WithUserAuthenticationTests.java | 8 ++++---- .../WithUserClassLevelAuthenticationTests.java | 8 ++++---- .../WithUserDetailsAuthenticationTests.java | 8 ++++---- ...thUserDetailsClassLevelAuthenticationTests.java | 8 ++++---- .../test/web/support/WebTestUtilsTests.java | 11 +++++------ 19 files changed, 71 insertions(+), 74 deletions(-) diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/Sec2935Tests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/Sec2935Tests.java index eb14f3173f..a9e0bec7a0 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/Sec2935Tests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/Sec2935Tests.java @@ -37,6 +37,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; @@ -132,11 +133,10 @@ public class Sec2935Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .httpBasic(); + .anyRequest().authenticated()) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationStatelessTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationStatelessTests.java index 1ff15e3d8f..62814874fa 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationStatelessTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationStatelessTests.java @@ -82,8 +82,8 @@ public class SecurityMockMvcRequestPostProcessorsAuthenticationStatelessTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests.java index f994130201..2be19b7a2e 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests.java @@ -63,7 +63,7 @@ public class SecurityMockMvcRequestPostProcessorsCsrfDebugFilterTests { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http.csrf().csrfTokenRepository(cookieCsrfTokenRepository); + http.csrf((csrf) -> csrf.csrfTokenRepository(cookieCsrfTokenRepository)); return http.build(); } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2ClientTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2ClientTests.java index 276cc5286f..a2fb282113 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2ClientTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2ClientTests.java @@ -60,6 +60,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Client; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -181,9 +182,9 @@ public class SecurityMockMvcRequestPostProcessorsOAuth2ClientTests { // @formatter:off http .authorizeRequests((authz) -> authz - .anyRequest().permitAll() + .anyRequest().permitAll() ) - .oauth2Client(); + .oauth2Client(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2LoginTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2LoginTests.java index f834d43165..eb64e86f63 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2LoginTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOAuth2LoginTests.java @@ -55,6 +55,7 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.mockito.Mockito.mock; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -158,9 +159,9 @@ public class SecurityMockMvcRequestPostProcessorsOAuth2LoginTests { // @formatter:off http .authorizeRequests((authorize) -> authorize - .requestMatchers("/admin/**").hasAuthority("SCOPE_admin") - .anyRequest().hasAuthority("SCOPE_read") - ).oauth2Login(); + .requestMatchers("/admin/**").hasAuthority("SCOPE_admin") + .anyRequest().hasAuthority("SCOPE_read") + ).oauth2Login(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOidcLoginTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOidcLoginTests.java index 418cd4f4e7..d02467ad87 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOidcLoginTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOidcLoginTests.java @@ -56,6 +56,7 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.mockito.Mockito.mock; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oidcLogin; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -155,11 +156,10 @@ public class SecurityMockMvcRequestPostProcessorsOidcLoginTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasAuthority("SCOPE_admin") - .anyRequest().hasAuthority("SCOPE_read") - .and() - .oauth2Login(); + .anyRequest().hasAuthority("SCOPE_read")) + .oauth2Login(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOpaqueTokenTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOpaqueTokenTests.java index 734a439c06..6cd177a44a 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOpaqueTokenTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsOpaqueTokenTests.java @@ -130,13 +130,12 @@ public class SecurityMockMvcRequestPostProcessorsOpaqueTokenTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasAuthority("SCOPE_admin") - .anyRequest().hasAuthority("SCOPE_read") - .and() - .oauth2ResourceServer() - .opaqueToken() - .introspector(mock(OpaqueTokenIntrospector.class)); + .anyRequest().hasAuthority("SCOPE_read")) + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken + .introspector(mock(OpaqueTokenIntrospector.class)))); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextStatelessTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextStatelessTests.java index af8d6ec607..90173d3a2d 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextStatelessTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextStatelessTests.java @@ -80,8 +80,8 @@ public class SecurityMockMvcRequestPostProcessorsTestSecurityContextStatelessTes SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/response/Gh3409Tests.java b/test/src/test/java/org/springframework/security/test/web/servlet/response/Gh3409Tests.java index 1e40bf04d2..a065a4fa7d 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/response/Gh3409Tests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/response/Gh3409Tests.java @@ -35,6 +35,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.securityContext; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; @@ -98,12 +99,11 @@ public class Gh3409Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/public/**").permitAll() - .anyRequest().authenticated() - .and() - .formLogin().and() - .httpBasic(); + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java index c1cd2098dd..b1ffca0d83 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java @@ -84,8 +84,8 @@ public class CustomCsrfShowcaseTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .csrfTokenRepository(repo()); + .csrf((csrf) -> csrf + .csrfTokenRepository(repo())); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java index e96998532d..c055705362 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java @@ -99,16 +99,14 @@ public class CustomConfigAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .securityContext() - .securityContextRepository(securityContextRepository()) - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .securityContext((context) -> context + .securityContextRepository(securityContextRepository())) + .formLogin((login) -> login .usernameParameter("user") .passwordParameter("pass") - .loginPage("/authenticate"); + .loginPage("/authenticate")); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java index a430b6e6f5..7048193d39 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java @@ -90,13 +90,12 @@ public class CustomLoginRequestBuilderAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login .usernameParameter("user") .passwordParameter("pass") - .loginPage("/authenticate"); + .loginPage("/authenticate")); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java index e00726209e..635d7a6024 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java @@ -35,6 +35,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; @@ -97,11 +98,10 @@ public class DefaultfSecurityRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .httpBasic(); + .anyRequest().authenticated()) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java index da358687a2..461d4a6d81 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java @@ -40,6 +40,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; @@ -112,11 +113,10 @@ public class SecurityRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .formLogin(); + .anyRequest().authenticated()) + .formLogin(withDefaults()); // @formatter:on return http.build(); } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java index 27ded9e526..662315cc5b 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java @@ -37,6 +37,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -97,11 +98,10 @@ public class WithUserAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .formLogin(); + .anyRequest().authenticated()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java index ec6b7fbc34..71ab53568f 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java @@ -37,6 +37,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; @@ -96,11 +97,10 @@ public class WithUserClassLevelAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .httpBasic(); + .anyRequest().authenticated()) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java index 9fbc66ecd0..2994ff9aeb 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java @@ -38,6 +38,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -87,11 +88,10 @@ public class WithUserDetailsAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .formLogin(); + .anyRequest().authenticated()) + .formLogin(withDefaults()); // @formatter:on return http.build(); } diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java index 2b44e71654..2827daf3b6 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java @@ -38,6 +38,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -86,11 +87,10 @@ public class WithUserDetailsClassLevelAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .formLogin(); + .anyRequest().authenticated()) + .formLogin(withDefaults()); // @formatter:on return http.build(); } diff --git a/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java index 496f403783..f1d973e5f6 100644 --- a/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java +++ b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java @@ -191,7 +191,7 @@ public class WebTestUtilsTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf().disable(); + http.csrf((csrf) -> csrf.disable()); return http.build(); } @@ -208,11 +208,10 @@ public class WebTestUtilsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .csrfTokenRepository(CSRF_REPO) - .and() - .securityContext() - .securityContextRepository(CONTEXT_REPO); + .csrf((csrf) -> csrf + .csrfTokenRepository(CSRF_REPO)) + .securityContext((context) -> context + .securityContextRepository(CONTEXT_REPO)); return http.build(); // @formatter:on } From 1435e0f3d312e2844ceae5780b39eba00a63fe9e Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:05:54 -0600 Subject: [PATCH 400/504] Use HttpSecurity Lambda DSL in Config Tests Issue gh-13067 --- .../annotation/issue50/SecurityConfig.java | 5 +- .../annotation/sec2758/Sec2758Tests.java | 4 +- ...RequestMatcherRegistryAnyMatcherTests.java | 30 +- .../web/builders/HttpConfigurationTests.java | 13 +- .../web/builders/NamespaceHttpTests.java | 110 ++--- .../web/builders/WebSecurityTests.java | 13 +- .../OAuth2ClientConfigurationTests.java | 29 +- ...ntextConfigurationResourceServerTests.java | 2 +- .../WebSecurityConfigurationTests.java | 16 +- .../configurers/AnonymousConfigurerTests.java | 7 +- .../AuthorizeHttpRequestsConfigurerTests.java | 66 ++- .../configurers/AuthorizeRequestsTests.java | 44 +- .../ChannelSecurityConfigurerTests.java | 36 +- .../web/configurers/CorsConfigurerTests.java | 28 +- ...onfigurerIgnoringRequestMatchersTests.java | 12 +- .../web/configurers/CsrfConfigurerTests.java | 88 ++-- .../web/configurers/DefaultFiltersTests.java | 7 +- .../DefaultLoginPageConfigurerTests.java | 58 +-- ...ingConfigurerAccessDeniedHandlerTests.java | 26 +- .../ExceptionHandlingConfigurerTests.java | 34 +- ...essionUrlAuthorizationConfigurerTests.java | 159 +++---- .../configurers/FormLoginConfigurerTests.java | 100 ++-- .../HeadersConfigurerEagerHeadersTests.java | 4 +- .../configurers/HeadersConfigurerTests.java | 152 +++--- .../configurers/HttpBasicConfigurerTests.java | 39 +- .../configurers/HttpSecurityLogoutTests.java | 6 +- .../HttpSecurityRequestMatchersTests.java | 47 +- ...ttpSecuritySecurityMatchersNoMvcTests.java | 7 +- .../HttpSecuritySecurityMatchersTests.java | 41 +- .../web/configurers/JeeConfigurerTests.java | 10 +- .../LogoutConfigurerClearSiteDataTests.java | 4 +- .../configurers/LogoutConfigurerTests.java | 48 +- .../NamespaceHttpAnonymousTests.java | 34 +- .../configurers/NamespaceHttpBasicTests.java | 27 +- .../NamespaceHttpCustomFilterTests.java | 10 +- .../NamespaceHttpExpressionHandlerTests.java | 4 +- .../NamespaceHttpFormLoginTests.java | 27 +- .../NamespaceHttpHeadersTests.java | 45 +- .../NamespaceHttpInterceptUrlTests.java | 9 +- .../configurers/NamespaceHttpJeeTests.java | 18 +- .../configurers/NamespaceHttpLogoutTests.java | 8 +- .../NamespaceHttpPortMappingsTests.java | 14 +- .../NamespaceHttpRequestCacheTests.java | 13 +- ...aceHttpServerAccessDeniedHandlerTests.java | 18 +- .../configurers/NamespaceHttpX509Tests.java | 53 +-- .../configurers/NamespaceRememberMeTests.java | 96 ++-- .../NamespaceSessionManagementTests.java | 52 +- .../configurers/PermitAllSupportTests.java | 40 +- .../PortMapperConfigurerTests.java | 13 +- .../RememberMeConfigurerTests.java | 70 ++- .../RequestCacheConfigurerTests.java | 16 +- .../RequestMatcherConfigurerTests.java | 14 +- .../SecurityContextConfigurerTests.java | 22 +- .../ServletApiConfigurerTests.java | 27 +- ...ionManagementConfigurerServlet31Tests.java | 6 +- ...rerSessionAuthenticationStrategyTests.java | 8 +- ...tConfigurerSessionCreationPolicyTests.java | 2 +- .../SessionManagementConfigurerTests.java | 51 +- ...onfigurerTransientAuthenticationTests.java | 4 +- .../UrlAuthorizationConfigurerTests.java | 9 +- .../configurers/UrlAuthorizationsTests.java | 4 +- .../web/configurers/X509ConfigurerTests.java | 9 +- .../client/OAuth2ClientConfigurerTests.java | 16 +- .../client/OAuth2LoginConfigurerTests.java | 114 +++-- .../OAuth2ResourceServerConfigurerTests.java | 447 ++++++++---------- .../saml2/Saml2LoginConfigurerTests.java | 2 +- .../saml2/Saml2LogoutConfigurerTests.java | 2 +- .../core/GrantedAuthorityDefaultsJcTests.java | 4 +- .../customconfigurer/CustomConfigurer.java | 8 +- .../CustomHttpSecurityConfigurerTests.java | 10 +- .../config/annotation/web/CorsDslTests.kt | 3 +- .../annotation/web/FormLoginDslTests.kt | 3 +- 72 files changed, 1185 insertions(+), 1392 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java b/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java index ba7d4a616c..4b338c116d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java +++ b/config/src/test/java/org/springframework/security/config/annotation/issue50/SecurityConfig.java @@ -51,9 +51,8 @@ public class SecurityConfig { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .requestMatchers(new AntPathRequestMatcher("/*")).permitAll() - .and() + .authorizeRequests((requests) -> requests + .requestMatchers(new AntPathRequestMatcher("/*")).permitAll()) .authenticationProvider(authenticationProvider()); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java b/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java index 7d4ecd7423..ced754e393 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/sec2758/Sec2758Tests.java @@ -87,8 +87,8 @@ public class Sec2758Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().access("hasAnyRole('CUSTOM')"); + .authorizeRequests((requests) -> requests + .anyRequest().access("hasAnyRole('CUSTOM')")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java index d740b41068..0a0b970968 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryAnyMatcherTests.java @@ -86,9 +86,9 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated() + .requestMatchers(new AntPathRequestMatcher("/demo/**")).permitAll()); return http.build(); // @formatter:on } @@ -103,9 +103,9 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .requestMatchers(new MvcRequestMatcher(introspector, "/demo/**")).permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated() + .requestMatchers(new MvcRequestMatcher(introspector, "/demo/**")).permitAll()); return http.build(); // @formatter:on } @@ -120,9 +120,9 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .requestMatchers(new RegexRequestMatcher(".*", null)).permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated() + .requestMatchers(new RegexRequestMatcher(".*", null)).permitAll()); return http.build(); // @formatter:on } @@ -137,9 +137,9 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .anyRequest().permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated() + .anyRequest().permitAll()); return http.build(); // @formatter:on } @@ -154,9 +154,9 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .requestMatchers(new AntPathRequestMatcher("/**")).permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated() + .requestMatchers(new AntPathRequestMatcher("/**")).permitAll()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java index e7326ab9f8..7a4cb72b10 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpConfigurationTests.java @@ -48,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -148,14 +149,12 @@ public class HttpConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers() + .securityMatchers((security) -> security .requestMatchers(new AntPathRequestMatcher("/api/**")) - .requestMatchers(new AntPathRequestMatcher("/oauth/**")) - .and() - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .httpBasic(); + .requestMatchers(new AntPathRequestMatcher("/oauth/**"))) + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java index e24b8d8f10..6aa7666b5d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java @@ -71,6 +71,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; @@ -293,9 +294,9 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .anyRequest().permitAll() - .accessDecisionManager(ACCESS_DECISION_MANAGER); + .accessDecisionManager(ACCESS_DECISION_MANAGER)); return http.build(); // @formatter:on } @@ -311,12 +312,11 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin").hasRole("ADMIN") - .anyRequest().authenticated() - .and() - .exceptionHandling() - .accessDeniedPage("/AccessDeniedPage"); + .anyRequest().authenticated()) + .exceptionHandling((handling) -> handling + .accessDeniedPage("/AccessDeniedPage")); return http.build(); // @formatter:on } @@ -338,10 +338,9 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -356,11 +355,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)); return http.build(); // @formatter:on } @@ -375,11 +373,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); // @formatter:on } @@ -395,14 +392,12 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/unsecure").permitAll() - .anyRequest().authenticated() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) - .and() - .formLogin(); + .anyRequest().authenticated()) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -417,11 +412,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().anonymous() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.NEVER); + .authorizeRequests((requests) -> requests + .anyRequest().anonymous()) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.NEVER)); return http.build(); // @formatter:on } @@ -436,13 +430,11 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/entry-point")) - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .exceptionHandling((handling) -> handling + .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/entry-point"))) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -472,11 +464,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .realmName("RealmConfig"); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic((basic) -> basic + .realmName("RealmConfig")); return http.build(); // @formatter:on } @@ -562,13 +553,11 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .securityContext() - .securityContextRepository(new NullSecurityContextRepository()) - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .securityContext((context) -> context + .securityContextRepository(new NullSecurityContextRepository())) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -588,11 +577,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .servletApi() - .disable(); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .servletApi((api) -> api + .disable()); return http.build(); // @formatter:on } @@ -607,8 +595,8 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()); return http.build(); // @formatter:on } @@ -641,10 +629,10 @@ public class NamespaceHttpTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/users**", "/sessions/**").hasRole("USER") .requestMatchers("/signup").permitAll() - .anyRequest().hasRole("USER"); + .anyRequest().hasRole("USER")); this.httpSecurity = http; return http.build(); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java index a8d18adf4a..2b58af889f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/builders/WebSecurityTests.java @@ -50,6 +50,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -137,9 +138,9 @@ public class WebSecurityTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -176,9 +177,9 @@ public class WebSecurityTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java index 83a247673a..106204efe5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java @@ -58,6 +58,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -272,10 +273,9 @@ public class OAuth2ClientConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2Login(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2Login(withDefaults()); return http.build(); // @formatter:on } @@ -311,10 +311,9 @@ public class OAuth2ClientConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2Login(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2Login(withDefaults()); return http.build(); // @formatter:on } @@ -330,10 +329,9 @@ public class OAuth2ClientConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2Login(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2Login(withDefaults()); return http.build(); // @formatter:on } @@ -369,10 +367,9 @@ public class OAuth2ClientConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2Login(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2Login(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java index 76001a2fac..eb57f56960 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/SecurityReactorContextConfigurationResourceServerTests.java @@ -113,7 +113,7 @@ public class SecurityReactorContextConfigurationResourceServerTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.securityContext().requireExplicitSave(false); + http.securityContext((context) -> context.requireExplicitSave(false)); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java index f96d67809e..afabd761ba 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java @@ -535,9 +535,9 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .anyRequest().authenticated() - .expressionHandler(EXPRESSION_HANDLER); + .expressionHandler(EXPRESSION_HANDLER)); return http.build(); // @formatter:on } @@ -563,8 +563,8 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()); return http.build(); // @formatter:on } @@ -616,8 +616,8 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()); return http.build(); // @formatter:on } @@ -649,8 +649,8 @@ public class WebSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()"); + .authorizeRequests((requests) -> requests + .anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java index 599434e2f4..49b5d7d962 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java @@ -110,11 +110,10 @@ public class AnonymousConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .anonymous() + .anonymous((anonymous) -> anonymous .key("key") - .principal("principal") - .and() - .anonymous(); + .principal("principal")) + .anonymous(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index 7d57cae201..ea79dda610 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -762,7 +762,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests(); + .authorizeHttpRequests(withDefaults()); // @formatter:on return http.build(); @@ -793,8 +793,8 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests() - .anyRequest(); + .authorizeHttpRequests((requests) -> requests + .anyRequest()); // @formatter:on return http.build(); @@ -849,8 +849,8 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests() - .anyRequest().access(authorizationManager); + .authorizeHttpRequests((requests) -> requests + .anyRequest().access(authorizationManager)); // @formatter:on return http.build(); @@ -899,12 +899,11 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().hasAnyAuthority("ROLE_USER") - ) - .build(); + ) + .build(); // @formatter:on } @@ -918,12 +917,11 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().hasAuthority("ROLE_USER") - ) - .build(); + ) + .build(); // @formatter:on } @@ -937,12 +935,11 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN") - ) - .build(); + ) + .build(); // @formatter:on } @@ -1014,12 +1011,11 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().denyAll() - ) - .build(); + ) + .build(); // @formatter:on } @@ -1050,13 +1046,12 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().authenticated() - ) - .authorizeHttpRequests(withDefaults()) - .build(); + ) + .authorizeHttpRequests(withDefaults()) + .build(); // @formatter:on } @@ -1090,12 +1085,11 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .httpBasic() - .and() - .authorizeHttpRequests((requests) -> requests + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests .anyRequest().authenticated() - ) - .build(); + ) + .build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java index 4bf3d4ef78..0b79c086a7 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java @@ -198,8 +198,8 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll(); + .authorizeRequests((requests) -> requests + .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll()); // @formatter:on return http.build(); } @@ -242,9 +242,9 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'") - .anyRequest().denyAll(); + .authorizeRequests((requests) -> requests + .requestMatchers(new AntPathRequestMatcher("/user/{user}", null, false)).access("#user == 'user'") + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -264,9 +264,9 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'") - .anyRequest().denyAll(); + .authorizeRequests((requests) -> requests + .requestMatchers(new AntPathRequestMatcher("/user/{userName}", null, false)).access("#userName == 'user'") + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -286,8 +286,8 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("ADMIN"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("ADMIN")); // @formatter:on return http.build(); } @@ -315,9 +315,9 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .requestMatchers("/path").denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .requestMatchers("/path").denyAll()); // @formatter:on return http.build(); } @@ -385,9 +385,9 @@ public class AuthorizeRequestsTests { .servletPath("/spring"); // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll()); // @formatter:on return http.build(); } @@ -455,9 +455,9 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .requestMatchers("/user/{userName}").access("#userName == 'user'"); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .requestMatchers("/user/{userName}").access("#userName == 'user'")); // @formatter:on return http.build(); } @@ -523,9 +523,9 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic().and() - .authorizeRequests() - .requestMatchers("/user").denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .requestMatchers("/user").denyAll()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java index 8ff4f51361..21cbc87af8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java @@ -46,6 +46,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; @@ -138,8 +139,8 @@ public class ChannelSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requiresChannel() - .anyRequest().requiresSecure(); + .requiresChannel((channel) -> channel + .anyRequest().requiresSecure()); return http.build(); // @formatter:on } @@ -168,10 +169,9 @@ public class ChannelSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requiresChannel() - .anyRequest().requiresSecure() - .and() - .requiresChannel(); + .requiresChannel((channel) -> channel + .anyRequest().requiresSecure()) + .requiresChannel(withDefaults()); return http.build(); // @formatter:on } @@ -204,13 +204,12 @@ public class ChannelSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .portMapper() - .portMapper(new PortMapperImpl()) - .and() - .requiresChannel() + .portMapper((mapper) -> mapper + .portMapper(new PortMapperImpl())) + .requiresChannel((channel) -> channel .redirectStrategy(new TestUrlRedirectStrategy()) .anyRequest() - .requiresSecure(); + .requiresSecure()); return http.build(); // @formatter:on } @@ -239,18 +238,17 @@ public class ChannelSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .portMapper() - .portMapper(new PortMapperImpl()) - .and() - .requiresChannel() + .portMapper((mapper) -> mapper + .portMapper(new PortMapperImpl())) + .requiresChannel((channel) -> channel .requestMatchers("/test-1") - .requiresSecure() + .requiresSecure() .requestMatchers("/test-2") - .requiresSecure() + .requiresSecure() .requestMatchers("/test-3") - .requiresSecure() + .requiresSecure() .anyRequest() - .requiresInsecure(); + .requiresInsecure()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java index e1ea28c637..a7935fdde5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java @@ -204,10 +204,9 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .cors(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .cors(withDefaults()); return http.build(); // @formatter:on } @@ -223,10 +222,9 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .cors(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .cors(withDefaults()); return http.build(); // @formatter:on } @@ -283,10 +281,9 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .cors(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .cors(withDefaults()); return http.build(); // @formatter:on } @@ -340,10 +337,9 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .cors(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .cors(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java index a9aab54ba0..bd22ccf67e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java @@ -108,9 +108,9 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() + .csrf((csrf) -> csrf .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path")) - .ignoringRequestMatchers(this.requestMatcher); + .ignoringRequestMatchers(this.requestMatcher)); return http.build(); // @formatter:on } @@ -149,9 +149,9 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() + .csrf((csrf) -> csrf .ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf")) - .ignoringRequestMatchers(this.requestMatcher); + .ignoringRequestMatchers(this.requestMatcher)); return http.build(); // @formatter:on } @@ -189,8 +189,8 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .ignoringRequestMatchers("/no-csrf"); + .csrf((csrf) -> csrf + .ignoringRequestMatchers("/no-csrf")); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java index a37a101fbc..ce08191199 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java @@ -676,8 +676,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .disable(); + .csrf((csrf) -> csrf + .disable()); return http.build(); // @formatter:on } @@ -707,13 +707,11 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .csrf() - .disable(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .csrf((csrf) -> csrf + .disable()); // @formatter:on return http.build(); } @@ -735,13 +733,11 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .csrf() - .csrfTokenRepository(REPO); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .csrf((csrf) -> csrf + .csrfTokenRepository(REPO)); // @formatter:on return http.build(); } @@ -761,10 +757,9 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .and() - .sessionManagement() - .invalidSessionUrl("/error/sessionError"); + .csrf(withDefaults()) + .sessionManagement((management) -> management + .invalidSessionUrl("/error/sessionError")); return http.build(); // @formatter:on } @@ -781,8 +776,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .requireCsrfProtectionMatcher(MATCHER); + .csrf((csrf) -> csrf + .requireCsrfProtectionMatcher(MATCHER)); return http.build(); // @formatter:on } @@ -816,10 +811,9 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .csrf() - .csrfTokenRepository(REPO); + .formLogin(withDefaults()) + .csrf((csrf) -> csrf + .csrfTokenRepository(REPO)); // @formatter:on return http.build(); } @@ -859,8 +853,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling() - .accessDeniedHandler(DENIED_HANDLER); + .exceptionHandling((handling) -> handling + .accessDeniedHandler(DENIED_HANDLER)); return http.build(); // @formatter:on } @@ -879,8 +873,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling() - .defaultAccessDeniedHandlerFor(DENIED_HANDLER, MATCHER); + .exceptionHandling((handling) -> handling + .defaultAccessDeniedHandlerFor(DENIED_HANDLER, MATCHER)); return http.build(); // @formatter:on } @@ -895,7 +889,7 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin(); + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -910,10 +904,9 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .logout() - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")); + .formLogin(withDefaults()) + .logout((logout) -> logout + .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))); return http.build(); // @formatter:on } @@ -928,8 +921,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .requireCsrfProtectionMatcher(null); + .csrf((csrf) -> csrf + .requireCsrfProtectionMatcher(null)); return http.build(); // @formatter:on } @@ -944,12 +937,10 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .formLogin() - .and() - .httpBasic(); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .formLogin(withDefaults()) + .httpBasic(withDefaults()); // @formatter:on return http.build(); } @@ -969,8 +960,8 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .sessionAuthenticationStrategy(null); + .csrf((csrf) -> csrf + .sessionAuthenticationStrategy(null)); return http.build(); // @formatter:on } @@ -987,10 +978,9 @@ public class CsrfConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .csrf() - .sessionAuthenticationStrategy(STRATEGY); + .formLogin(withDefaults()) + .csrf((csrf) -> csrf + .sessionAuthenticationStrategy(STRATEGY)); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java index e5a3b3cc0b..46d0fbe54a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultFiltersTests.java @@ -63,6 +63,7 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -170,7 +171,7 @@ public class DefaultFiltersTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { TestHttpSecurities.disableDefaults(http); - http.formLogin(); + http.formLogin(withDefaults()); return http.build(); } @@ -190,8 +191,8 @@ public class DefaultFiltersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java index 4a1c9d05d7..61156188e1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java @@ -387,10 +387,9 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -410,13 +409,11 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .logout() - .logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler()) - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .logout((logout) -> logout + .logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -431,13 +428,11 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .logout() - .logoutSuccessUrl("/login?logout") - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .logout((logout) -> logout + .logoutSuccessUrl("/login?logout")) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -452,12 +447,10 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -477,13 +470,11 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling() - .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) - .and() - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin(); + .exceptionHandling((handling) -> handling + .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))) + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -500,9 +491,8 @@ public class DefaultLoginPageConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling() - .and() - .formLogin(); + .exceptionHandling(withDefaults()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java index e9097fd9c1..5b92a1af89 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java @@ -87,16 +87,15 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .exceptionHandling() + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .exceptionHandling((handling) -> handling .defaultAccessDeniedHandlerFor( - this.teapotDeniedHandler, - new AntPathRequestMatcher("/hello/**")) + this.teapotDeniedHandler, + new AntPathRequestMatcher("/hello/**")) .defaultAccessDeniedHandlerFor( - new AccessDeniedHandlerImpl(), - AnyRequestMatcher.INSTANCE); + new AccessDeniedHandlerImpl(), + AnyRequestMatcher.INSTANCE)); return http.build(); // @formatter:on } @@ -146,13 +145,12 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .exceptionHandling() + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .exceptionHandling((handling) -> handling .defaultAccessDeniedHandlerFor( - this.teapotDeniedHandler, - new AntPathRequestMatcher("/hello/**")); + this.teapotDeniedHandler, + new AntPathRequestMatcher("/hello/**"))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java index d89526127e..07b4a274bb 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java @@ -52,6 +52,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; @@ -241,7 +242,7 @@ public class ExceptionHandlingConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling(); + .exceptionHandling(withDefaults()); return http.build(); // @formatter:on } @@ -291,12 +292,10 @@ public class ExceptionHandlingConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic(withDefaults()) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -330,12 +329,10 @@ public class ExceptionHandlingConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic(withDefaults()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -352,12 +349,11 @@ public class ExceptionHandlingConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(AEP).and() - .exceptionHandling(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .exceptionHandling((handling) -> handling + .authenticationEntryPoint(AEP)) + .exceptionHandling(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java index ebb6b48bae..836d638e3f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java @@ -70,6 +70,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; @@ -566,8 +567,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("ROLE_USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("ROLE_USER")); return http.build(); // @formatter:on } @@ -584,8 +585,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")); return http.build(); // @formatter:on } @@ -605,7 +606,7 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests(); + .authorizeRequests(withDefaults()); return http.build(); // @formatter:on } @@ -621,9 +622,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/a").authenticated() - .anyRequest(); + .anyRequest()); return http.build(); // @formatter:on } @@ -638,10 +639,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().hasAnyAuthority("ROLE_USER"); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyAuthority("ROLE_USER")); return http.build(); // @formatter:on } @@ -656,10 +656,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().hasAuthority("ROLE_USER"); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().hasAuthority("ROLE_USER")); return http.build(); // @formatter:on } @@ -674,10 +673,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN"); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")); return http.build(); // @formatter:on } @@ -692,8 +690,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER")); return http.build(); // @formatter:on } @@ -708,8 +706,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER")); return http.build(); // @formatter:on } @@ -729,8 +727,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER")); return http.build(); // @formatter:on } @@ -750,8 +748,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER", "ADMIN"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER", "ADMIN")); return http.build(); // @formatter:on } @@ -766,8 +764,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER", "ADMIN"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER", "ADMIN")); return http.build(); // @formatter:on } @@ -787,8 +785,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasAnyRole("USER", "ADMIN"); + .authorizeRequests((requests) -> requests + .anyRequest().hasAnyRole("USER", "ADMIN")); return http.build(); // @formatter:on } @@ -808,10 +806,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().hasIpAddress("192.168.1.0"); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().hasIpAddress("192.168.1.0")); return http.build(); // @formatter:on } @@ -826,10 +823,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().anonymous(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().anonymous()); return http.build(); // @formatter:on } @@ -844,12 +840,10 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .rememberMe() - .and() - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().rememberMe(); + .rememberMe(withDefaults()) + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().rememberMe()); // @formatter:on return http.build(); } @@ -869,10 +863,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); return http.build(); // @formatter:on } @@ -887,10 +880,9 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().not().denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().not().denyAll()); return http.build(); // @formatter:on } @@ -905,12 +897,10 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .rememberMe() - .and() - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().fullyAuthenticated(); + .rememberMe(withDefaults()) + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().fullyAuthenticated()); return http.build(); // @formatter:on } @@ -930,12 +920,10 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .rememberMe() - .and() - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().access("hasRole('ROLE_USER') or request.method == 'GET'"); + .rememberMe(withDefaults()) + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().access("hasRole('ROLE_USER') or request.method == 'GET'")); return http.build(); // @formatter:on } @@ -955,12 +943,10 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .authorizeRequests() - .anyRequest().authenticated() - .and() - .authorizeRequests(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .authorizeRequests(withDefaults()); return http.build(); // @formatter:on } @@ -979,14 +965,13 @@ public class ExpressionUrlAuthorizationConfigurerTests { AffirmativeBased adm = new AffirmativeBased(Collections.singletonList(expressionVoter)); // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .expressionHandler(handler) .accessDecisionManager(adm) .filterSecurityInterceptorOncePerRequest(true) .requestMatchers("/a", "/b").hasRole("ADMIN") - .anyRequest().permitAll() - .and() - .formLogin(); + .anyRequest().permitAll()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -1001,7 +986,7 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .anyRequest().permitAll() .withObjectPostProcessor(new ObjectPostProcessor() { @Override @@ -1010,7 +995,7 @@ public class ExpressionUrlAuthorizationConfigurerTests { fsi.setPublishAuthorizationSuccess(true); return fsi; } - }); + })); return http.build(); // @formatter:on } @@ -1046,11 +1031,11 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/admin").hasRole("ADMIN") .requestMatchers("/user").hasRole("USER") .requestMatchers("/allow").access("@permission.check(authentication,'user')") - .anyRequest().access("@permission.check(authentication,'admin')"); + .anyRequest().access("@permission.check(authentication,'admin')")); return http.build(); // @formatter:on } @@ -1079,12 +1064,12 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .expressionHandler(expressionHandler()) .requestMatchers("/admin").hasRole("ADMIN") .requestMatchers("/user").hasRole("USER") .requestMatchers("/allow").access("check('user')") - .anyRequest().access("check('admin')"); + .anyRequest().access("check('admin')")); return http.build(); // @formatter:on } @@ -1133,8 +1118,8 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()); // @formatter:on return http.build(); } @@ -1160,12 +1145,12 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/allow").access("hasPermission('ID', 'TYPE', 'PERMISSION')") .requestMatchers("/allowObject").access("hasPermission('TESTOBJ', 'PERMISSION')") .requestMatchers("/deny").access("hasPermission('ID', 'TYPE', 'NO PERMISSION')") .requestMatchers("/denyObject").access("hasPermission('TESTOBJ', 'NO PERMISSION')") - .anyRequest().permitAll(); + .anyRequest().permitAll()); return http.build(); // @formatter:on } @@ -1198,10 +1183,10 @@ public class ExpressionUrlAuthorizationConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/allow").access("hasRole('MEMBER')") .requestMatchers("/deny").access("hasRole('ADMIN')") - .anyRequest().permitAll(); + .anyRequest().permitAll()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java index bea1f943d8..8401ef354e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java @@ -396,9 +396,9 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin().and() - .requestCache() - .requestCache(this.requestCache); + .formLogin(withDefaults()) + .requestCache((cache) -> cache + .requestCache(this.requestCache)); return http.build(); // @formatter:on } @@ -430,11 +430,10 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .loginPage("/login"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login + .loginPage("/login")); // @formatter:on return http.build(); } @@ -478,11 +477,10 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login + .permitAll()); return http.build(); // @formatter:on } @@ -497,15 +495,13 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login .loginPage("/authenticate") - .permitAll() - .and() - .logout() - .permitAll(); + .permitAll()) + .logout((logout) -> logout + .permitAll()); return http.build(); // @formatter:on } @@ -544,21 +540,19 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login .loginProcessingUrl("/loginCheck") .loginPage("/login") .defaultSuccessUrl("/", true) .passwordParameter("password") .usernameParameter("username") - .permitAll() - .and() - .logout() + .permitAll()) + .logout((logout) -> logout .logoutSuccessUrl("/login") .logoutUrl("/logout") - .deleteCookies("JSESSIONID"); + .deleteCookies("JSESSIONID")); // @formatter:on return http.build(); } @@ -616,14 +610,12 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .permitAll() - .and() - .portMapper() - .portMapper(PORT_MAPPER); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login + .permitAll()) + .portMapper((mapper) -> mapper + .portMapper(PORT_MAPPER)); // @formatter:on LoginUrlAuthenticationEntryPoint authenticationEntryPoint = (LoginUrlAuthenticationEntryPoint) http .getConfigurer(FormLoginConfigurer.class) @@ -644,12 +636,11 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login .failureHandler(FAILURE_HANDLER) - .permitAll(); + .permitAll()); return http.build(); // @formatter:on } @@ -664,10 +655,9 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .usernameParameter("custom-username") - .and() - .formLogin(); + .formLogin((login) -> login + .usernameParameter("custom-username")) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -687,15 +677,14 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .disable() - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() + .csrf((csrf) -> csrf + .disable()) + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login .failureForwardUrl("/failure_forward_url") .successForwardUrl("/success_forward_url") - .permitAll(); + .permitAll()); // @formatter:on return http.build(); } @@ -717,9 +706,8 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .exceptionHandling() - .and() - .formLogin(); + .exceptionHandling(withDefaults()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java index 2a75aa5cc9..1525b8cfbd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerEagerHeadersTests.java @@ -71,14 +71,14 @@ public class HeadersConfigurerEagerHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .addObjectPostProcessor(new ObjectPostProcessor() { @Override public HeaderWriterFilter postProcess(HeaderWriterFilter filter) { filter.setShouldWriteHeadersEagerly(true); return filter; } - }); + })); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java index 6c1d75786d..1b68c27628 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.test.SpringTestContext; @@ -582,7 +583,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers(); + .headers(withDefaults()); return http.build(); // @formatter:on } @@ -612,9 +613,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .contentTypeOptions(); + .contentTypeOptions(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -648,9 +649,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .frameOptions(); + .frameOptions(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -665,9 +666,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpStrictTransportSecurity(); + .httpStrictTransportSecurity(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -682,9 +683,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .cacheControl(); + .cacheControl(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -718,9 +719,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .xssProtection(); + .xssProtection(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -735,10 +736,10 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .xssProtection() - .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK); + .xssProtection((xss) -> xss + .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))); // @formatter:on return http.build(); } @@ -791,8 +792,8 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() - .frameOptions().sameOrigin(); + .headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions.sameOrigin())); return http.build(); // @formatter:on } @@ -825,9 +826,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning(); + .httpPublicKeyPinning(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -842,10 +843,10 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() - .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="); + .httpPublicKeyPinning((hpkp) -> hpkp + .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="))); return http.build(); // @formatter:on } @@ -863,10 +864,9 @@ public class HeadersConfigurerTests { pins.put("E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=", "sha256"); // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() - .withPins(pins); + .httpPublicKeyPinning((hpkp) -> hpkp.withPins(pins))); return http.build(); // @formatter:on } @@ -881,11 +881,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") - .maxAgeInSeconds(604800); + .maxAgeInSeconds(604800))); return http.build(); // @formatter:on } @@ -900,11 +900,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") - .reportOnly(false); + .reportOnly(false))); return http.build(); // @formatter:on } @@ -919,11 +919,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") - .includeSubDomains(true); + .includeSubDomains(true))); return http.build(); // @formatter:on } @@ -938,11 +938,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") - .reportUri(new URI("https://example.net/pkp-report")); + .reportUri(URI.create("https://example.net/pkp-report")))); return http.build(); // @formatter:on } @@ -957,11 +957,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning() + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") - .reportUri("https://example.net/pkp-report"); + .reportUri("https://example.net/pkp-report"))); return http.build(); // @formatter:on } @@ -999,9 +999,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .contentSecurityPolicy("default-src 'self'"); + .contentSecurityPolicy((csp) -> csp.policyDirectives("default-src 'self'"))); return http.build(); // @formatter:on } @@ -1016,10 +1016,11 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .contentSecurityPolicy("default-src 'self'; script-src trustedscripts.example.com") - .reportOnly(); + .contentSecurityPolicy((csp) -> csp + .policyDirectives("default-src 'self'; script-src trustedscripts.example.com") + .reportOnly())); return http.build(); // @formatter:on } @@ -1057,9 +1058,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .contentSecurityPolicy(""); + .contentSecurityPolicy((csp) -> csp.policyDirectives(""))); return http.build(); // @formatter:on } @@ -1114,9 +1115,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .referrerPolicy(); + .referrerPolicy(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1134,7 +1135,7 @@ public class HeadersConfigurerTests { .headers((headers) -> headers .defaultsDisabled() - .referrerPolicy() + .referrerPolicy(Customizer.withDefaults()) ); return http.build(); // @formatter:on @@ -1150,9 +1151,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .referrerPolicy(ReferrerPolicy.SAME_ORIGIN); + .referrerPolicy((referrer) -> referrer.policy(ReferrerPolicy.SAME_ORIGIN))); return http.build(); // @formatter:on } @@ -1188,9 +1189,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .featurePolicy("geolocation 'self'"); + .featurePolicy("geolocation 'self'")); return http.build(); // @formatter:on } @@ -1205,9 +1206,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .featurePolicy(""); + .featurePolicy("")); return http.build(); // @formatter:on } @@ -1222,9 +1223,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy("geolocation=(self)")); + .permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy("geolocation=(self)"))); return http.build(); // @formatter:on } @@ -1239,10 +1240,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .permissionsPolicy() - .policy("geolocation=(self)"); + .permissionsPolicy((permissions) -> permissions.policy("geolocation=(self)"))); return http.build(); // @formatter:on } @@ -1257,9 +1257,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy(null)); + .permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy(null))); return http.build(); // @formatter:on } @@ -1274,10 +1274,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .permissionsPolicy() - .policy(""); + .permissionsPolicy((permissions) -> permissions.policy(""))); return http.build(); // @formatter:on } @@ -1292,10 +1291,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpStrictTransportSecurity() - .preload(true); + .httpStrictTransportSecurity((hsts) -> hsts.preload(true))); return http.build(); // @formatter:on } @@ -1353,16 +1351,14 @@ public class HeadersConfigurerTests { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // @formatter:off - http.headers() - .defaultsDisabled() - .crossOriginOpenerPolicy() - .policy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN) - .and() - .crossOriginEmbedderPolicy() - .policy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP) - .and() - .crossOriginResourcePolicy() - .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN); + http.headers((headers) -> headers + .defaultsDisabled() + .crossOriginOpenerPolicy((opener) -> opener + .policy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN)) + .crossOriginEmbedderPolicy((embedder) -> embedder + .policy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)) + .crossOriginResourcePolicy((resource) -> resource + .policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN))); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java index 421289ddf4..ce019a7f1d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java @@ -221,7 +221,7 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic(); + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -274,10 +274,9 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic(withDefaults()); // @formatter:on return http.build(); } @@ -299,11 +298,10 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .authenticationEntryPoint(ENTRY_POINT); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic((basic) -> basic + .authenticationEntryPoint(ENTRY_POINT)); // @formatter:on return http.build(); } @@ -325,13 +323,11 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .authenticationEntryPoint(ENTRY_POINT) - .and() - .httpBasic(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic((basic) -> basic + .authenticationEntryPoint(ENTRY_POINT)) + .httpBasic(withDefaults()); // @formatter:on return http.build(); } @@ -351,9 +347,8 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .rememberMe(); + .httpBasic(withDefaults()) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -397,8 +392,8 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .securityContextRepository(SECURITY_CONTEXT_REPOSITORY); + .httpBasic((basic) -> basic + .securityContextRepository(SECURITY_CONTEXT_REPOSITORY)); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java index a635aa6cad..b82c2a57a3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityLogoutTests.java @@ -100,9 +100,9 @@ public class HttpSecurityLogoutTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf().disable() - .logout() - .clearAuthentication(false); + .csrf((csrf) -> csrf.disable()) + .logout((logout) -> logout + .clearAuthentication(false)); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java index 52f97c4a3e..73a03f4cad 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java @@ -222,14 +222,12 @@ public class HttpSecurityRequestMatchersTests { MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); // @formatter:off http - .securityMatchers() + .securityMatchers((security) -> security .requestMatchers(mvcMatcherBuilder.pattern("/test-1")) .requestMatchers(mvcMatcherBuilder.pattern("/test-2")) - .requestMatchers(mvcMatcherBuilder.pattern("/test-3")) - .and() - .authorizeRequests() - .anyRequest().denyAll() - .and() + .requestMatchers(mvcMatcherBuilder.pattern("/test-3"))) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) .httpBasic(withDefaults()); // @formatter:on return http.build(); @@ -240,11 +238,10 @@ public class HttpSecurityRequestMatchersTests { MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); // @formatter:off http - .securityMatchers() - .requestMatchers(mvcMatcherBuilder.pattern("/test-1")) - .and() - .authorizeRequests() - .anyRequest().permitAll(); + .securityMatchers((security) -> security + .requestMatchers(mvcMatcherBuilder.pattern("/test-1"))) + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()); // @formatter:on return http.build(); } @@ -271,9 +268,9 @@ public class HttpSecurityRequestMatchersTests { // @formatter:off http .securityMatcher(new MvcRequestMatcher(introspector, "/path")) - .httpBasic().and() - .authorizeRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -304,12 +301,11 @@ public class HttpSecurityRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { // @formatter:off http - .securityMatchers() - .requestMatchers(new MvcRequestMatcher(introspector, "/path")) - .and() - .httpBasic().and() - .authorizeRequests() - .anyRequest().denyAll(); + .securityMatchers((security) -> security + .requestMatchers(new MvcRequestMatcher(introspector, "/path"))) + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -376,13 +372,12 @@ public class HttpSecurityRequestMatchersTests { mvcMatcherBuilder.servletPath("/spring"); // @formatter:off http - .securityMatchers() + .securityMatchers((security) -> security .requestMatchers(mvcMatcherBuilder.pattern("/path")) - .requestMatchers("/never-match") - .and() - .httpBasic().and() - .authorizeRequests() - .anyRequest().denyAll(); + .requestMatchers("/never-match")) + .httpBasic(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java index d56c40d9e2..7dca1b7b5e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java @@ -45,6 +45,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Marcus Da Coregio @@ -121,9 +122,9 @@ public class HttpSecuritySecurityMatchersNoMvcTests { // @formatter:off http .securityMatcher("/path") - .httpBasic().and() - .authorizeHttpRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java index 3f70043e67..b476c45c38 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java @@ -222,14 +222,12 @@ public class HttpSecuritySecurityMatchersTests { SecurityFilterChain first(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers() + .securityMatchers((security) -> security .requestMatchers("/test-1") .requestMatchers("/test-2") - .requestMatchers("/test-3") - .and() - .authorizeHttpRequests() - .anyRequest().denyAll() - .and() + .requestMatchers("/test-3")) + .authorizeHttpRequests((requests) -> requests + .anyRequest().denyAll()) .httpBasic(withDefaults()); // @formatter:on return http.build(); @@ -239,11 +237,10 @@ public class HttpSecuritySecurityMatchersTests { SecurityFilterChain second(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers() - .requestMatchers("/test-1") - .and() - .authorizeHttpRequests() - .anyRequest().permitAll(); + .securityMatchers((security) -> security + .requestMatchers("/test-1")) + .authorizeHttpRequests((requests) -> requests + .anyRequest().permitAll()); // @formatter:on return http.build(); } @@ -271,9 +268,9 @@ public class HttpSecuritySecurityMatchersTests { // @formatter:off http .securityMatcher("/path") - .httpBasic().and() - .authorizeHttpRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -301,9 +298,9 @@ public class HttpSecuritySecurityMatchersTests { // @formatter:off http .securityMatcher("/path") - .httpBasic().and() - .authorizeHttpRequests() - .anyRequest().denyAll(); + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } @@ -364,13 +361,13 @@ public class HttpSecuritySecurityMatchersTests { .servletPath("/spring"); // @formatter:off http - .securityMatchers() + .securityMatchers((security) -> security .requestMatchers(mvcMatcherBuilder.pattern("/path")) .requestMatchers(mvcMatcherBuilder.pattern("/never-match")) - .and() - .httpBasic().and() - .authorizeHttpRequests() - .anyRequest().denyAll(); + ) + .httpBasic(withDefaults()) + .authorizeHttpRequests((requests) -> requests + .anyRequest().denyAll()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java index 327c755a6a..527933f178 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java @@ -44,6 +44,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -162,7 +163,7 @@ public class JeeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .jee(); + .jee(withDefaults()); return http.build(); // @formatter:on } @@ -191,10 +192,9 @@ public class JeeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .jee() - .mappableRoles("USER") - .and() - .jee(); + .jee((jee) -> jee + .mappableRoles("USER")) + .jee(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerClearSiteDataTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerClearSiteDataTests.java index 2a8f102a0f..7cae3927d7 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerClearSiteDataTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerClearSiteDataTests.java @@ -97,8 +97,8 @@ public class LogoutConfigurerClearSiteDataTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE))); + .logout((logout) -> logout + .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE)))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java index ea62cd7046..b8414c53fd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java @@ -56,6 +56,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -414,8 +415,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class)); + .logout((logout) -> logout + .defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class))); return http.build(); // @formatter:on } @@ -447,8 +448,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null); + .logout((logout) -> logout + .defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null)); return http.build(); // @formatter:on } @@ -482,7 +483,7 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout(); + .logout(withDefaults()); return http.build(); // @formatter:on } @@ -511,10 +512,9 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .logoutUrl("/custom/logout") - .and() - .logout(); + .logout((logout) -> logout + .logoutUrl("/custom/logout")) + .logout(withDefaults()); // @formatter:on return http.build(); } @@ -534,9 +534,9 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .disable() - .logout(); + .csrf((csrf) -> csrf + .disable()) + .logout(withDefaults()); return http.build(); // @formatter:on } @@ -551,10 +551,10 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .disable() - .logout() - .logoutUrl("/custom/logout"); + .csrf((csrf) -> csrf + .disable()) + .logout((logout) -> logout + .logoutUrl("/custom/logout")); return http.build(); // @formatter:on } @@ -569,8 +569,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf() - .disable() + .csrf((csrf) -> csrf + .disable()) .logout((logout) -> logout.logoutUrl("/custom/logout")); return http.build(); // @formatter:on @@ -586,8 +586,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .addLogoutHandler(null); + .logout((logout) -> logout + .addLogoutHandler(null)); return http.build(); // @formatter:on } @@ -619,8 +619,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .rememberMe() - .rememberMeServices(REMEMBER_ME); + .rememberMe((me) -> me + .rememberMeServices(REMEMBER_ME)); return http.build(); // @formatter:on } @@ -641,8 +641,8 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .disable(); + .logout((logout) -> logout + .disable()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java index 46839372cf..e0128d8ae2 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpAnonymousTests.java @@ -99,9 +99,9 @@ public class NamespaceHttpAnonymousTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/type").anonymous() - .anyRequest().denyAll(); + .anyRequest().denyAll()); return http.build(); // @formatter:on } @@ -116,10 +116,9 @@ public class NamespaceHttpAnonymousTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().permitAll() - .and() - .anonymous().disable(); + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .anonymous((anonymous) -> anonymous.disable()); // @formatter:on return http.build(); } @@ -140,12 +139,11 @@ public class NamespaceHttpAnonymousTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/type").hasRole("ANON") - .anyRequest().denyAll() - .and() - .anonymous() - .authorities("ROLE_ANON"); + .anyRequest().denyAll()) + .anonymous((anonymous) -> anonymous + .authorities("ROLE_ANON")); return http.build(); // @formatter:on } @@ -161,11 +159,10 @@ public class NamespaceHttpAnonymousTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/key").anonymous() - .anyRequest().denyAll() - .and() - .anonymous().key("AnonymousKeyConfig"); + .anyRequest().denyAll()) + .anonymous((anonymous) -> anonymous.key("AnonymousKeyConfig")); return http.build(); // @formatter:on } @@ -181,11 +178,10 @@ public class NamespaceHttpAnonymousTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/principal").anonymous() - .anyRequest().denyAll() - .and() - .anonymous().principal("AnonymousUsernameConfig"); + .anyRequest().denyAll()) + .anonymous((anonymous) -> anonymous.principal("AnonymousUsernameConfig")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java index 1ffc8d349c..c1fa89078a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java @@ -183,10 +183,9 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .httpBasic(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -220,10 +219,9 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .httpBasic().realmName("Custom Realm"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .httpBasic((basic) -> basic.realmName("Custom Realm")); return http.build(); // @formatter:on } @@ -260,8 +258,8 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .authenticationDetailsSource(this.authenticationDetailsSource); + .httpBasic((basic) -> basic + .authenticationDetailsSource(this.authenticationDetailsSource)); return http.build(); // @formatter:on } @@ -307,11 +305,10 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .httpBasic() - .authenticationEntryPoint(this.authenticationEntryPoint); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .httpBasic((basic) -> basic + .authenticationEntryPoint(this.authenticationEntryPoint)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java index 36920cd85a..2ff73da375 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpCustomFilterTests.java @@ -48,6 +48,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic import org.springframework.web.filter.OncePerRequestFilter; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * Tests to verify that all the functionality of <custom-filter> attributes is @@ -110,7 +111,7 @@ public class NamespaceHttpCustomFilterTests { // @formatter:off http .addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class) - .formLogin(); + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -126,7 +127,7 @@ public class NamespaceHttpCustomFilterTests { // @formatter:off http .addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class) - .formLogin(); + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -181,9 +182,8 @@ public class NamespaceHttpCustomFilterTests { // @formatter:off TestHttpSecurities.disableDefaults(http); http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) .addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java index 37cbeb59bb..d9738431e4 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpExpressionHandlerTests.java @@ -99,9 +99,9 @@ public class NamespaceHttpExpressionHandlerTests { handler.setExpressionParser(expressionParser()); // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .expressionHandler(handler) - .anyRequest().access("hasRole('USER')"); + .anyRequest().access("hasRole('USER')")); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java index c1bd55dbdb..54b0e5ca87 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java @@ -42,6 +42,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -124,10 +125,9 @@ public class NamespaceHttpFormLoginTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()); return http.build(); // @formatter:on } @@ -143,16 +143,15 @@ public class NamespaceHttpFormLoginTests { boolean alwaysUseDefaultSuccess = true; // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login .usernameParameter("username") // form-login@username-parameter .passwordParameter("password") // form-login@password-parameter .loginPage("/authentication/login") // form-login@login-page .failureUrl("/authentication/login?failed") // form-login@authentication-failure-url .loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url - .defaultSuccessUrl("/default", alwaysUseDefaultSuccess); + .defaultSuccessUrl("/default", alwaysUseDefaultSuccess)); return http.build(); // form-login@default-target-url / form-login@always-use-default-target // @formatter:on } @@ -169,15 +168,13 @@ public class NamespaceHttpFormLoginTests { successHandler.setDefaultTargetUrl("/custom/targetUrl"); // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin((login) -> login .loginPage("/login") .failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref .successHandler(successHandler) // form-login@authentication-success-handler-ref - .authenticationDetailsSource(authenticationDetailsSource()) // form-login@authentication-details-source-ref - .and(); + .authenticationDetailsSource(authenticationDetailsSource())); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java index 97fc903076..4a59f2312e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpHeadersTests.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.test.SpringTestContext; @@ -41,6 +42,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultMatcher; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; @@ -161,7 +163,7 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers(); + .headers(withDefaults()); return http.build(); // @formatter:on } @@ -176,9 +178,9 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .cacheControl(); + .cacheControl(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -193,9 +195,9 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .httpStrictTransportSecurity(); + .httpStrictTransportSecurity(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -210,13 +212,13 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains .defaultsDisabled() - .httpStrictTransportSecurity() + .httpStrictTransportSecurity((hsts) -> hsts .requestMatcher(AnyRequestMatcher.INSTANCE) .maxAgeInSeconds(15768000) - .includeSubDomains(false); + .includeSubDomains(false))); return http.build(); // @formatter:on } @@ -231,11 +233,10 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // frame-options@policy=SAMEORIGIN .defaultsDisabled() - .frameOptions() - .sameOrigin(); + .frameOptions((frameOptions) -> frameOptions.sameOrigin())); return http.build(); // @formatter:on } @@ -250,11 +251,11 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // frame-options@ref .defaultsDisabled() .addHeaderWriter(new XFrameOptionsHeaderWriter( - new StaticAllowFromStrategy(URI.create("https://example.com")))); + new StaticAllowFromStrategy(URI.create("https://example.com"))))); return http.build(); // @formatter:on } @@ -269,10 +270,10 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // xss-protection .defaultsDisabled() - .xssProtection(); + .xssProtection(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -287,11 +288,11 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // xss-protection@enabled and xss-protection@block .defaultsDisabled() - .xssProtection() - .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK); + .xssProtection((xss) -> xss + .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))); // @formatter:on return http.build(); } @@ -306,10 +307,10 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers // content-type-options .defaultsDisabled() - .contentTypeOptions(); + .contentTypeOptions(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -324,9 +325,9 @@ public class NamespaceHttpHeadersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers() + .headers((headers) -> headers .defaultsDisabled() - .addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue")); + .addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java index 37cc5ea2c2..9b10de45ea 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpInterceptUrlTests.java @@ -118,7 +118,7 @@ public class NamespaceHttpInterceptUrlTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests().requestMatchers( + .authorizeRequests((requests) -> requests.requestMatchers( // the line below is similar to intercept-url@pattern: // //" access="hasRole('ROLE_ADMIN')"/> @@ -128,14 +128,13 @@ public class NamespaceHttpInterceptUrlTests { //" access="hasRole('ROLE_ADMIN')" method="POST"/> HttpMethod.POST, "/admin/post", "/admin/another-post/**").hasRole("ADMIN") .requestMatchers("/signup").permitAll() - .anyRequest().hasRole("USER") - .and() - .requiresChannel().requestMatchers("/login", "/secured/**") + .anyRequest().hasRole("USER")) + .requiresChannel((channel) -> channel.requestMatchers("/login", "/secured/**") // NOTE: channel security is configured separately of authorization (i.e. intercept-url@access // the line below is similar to intercept-url@requires-channel="https": // //" requires-channel="https"/> - .requiresSecure().anyRequest().requiresInsecure(); + .requiresSecure().anyRequest().requiresInsecure()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java index dad9820b34..b5edd3b5b1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpJeeTests.java @@ -104,11 +104,10 @@ public class NamespaceHttpJeeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("user") - .and() - .jee() - .mappableRoles("user", "admin"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("user")) + .jee((jee) -> jee + .mappableRoles("user", "admin")); return http.build(); // @formatter:on } @@ -126,12 +125,11 @@ public class NamespaceHttpJeeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("user") - .and() - .jee() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("user")) + .jee((jee) -> jee .mappableAuthorities("ROLE_user", "ROLE_admin") - .authenticatedUserDetailsService(this.authenticationUserDetailsService); + .authenticatedUserDetailsService(this.authenticationUserDetailsService)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java index 3d00e909d3..7f8858b964 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java @@ -196,11 +196,11 @@ public class NamespaceHttpLogoutTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() + .logout((logout) -> logout .deleteCookies("remove") // logout@delete-cookies .invalidateHttpSession(false) // logout@invalidate-session=false (default is true) .logoutUrl("/custom-logout") // logout@logout-url (default is /logout) - .logoutSuccessUrl("/logout-success"); + .logoutSuccessUrl("/logout-success")); return http.build(); // logout@success-url (default is /login?logout) // @formatter:on } @@ -237,8 +237,8 @@ public class NamespaceHttpLogoutTests { logoutSuccessHandler.setDefaultTargetUrl("/SuccessHandlerRefHttpLogoutConfig"); // @formatter:off http - .logout() - .logoutSuccessHandler(logoutSuccessHandler); + .logout((logout) -> logout + .logoutSuccessHandler(logoutSuccessHandler)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpPortMappingsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpPortMappingsTests.java index 382772a21a..474de9516e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpPortMappingsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpPortMappingsTests.java @@ -70,15 +70,13 @@ public class NamespaceHttpPortMappingsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .portMapper() - .http(9080).mapsTo(9443) - .and() - .requiresChannel() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .portMapper((mapper) -> mapper + .http(9080).mapsTo(9443)) + .requiresChannel((channel) -> channel .requestMatchers("/login", "/secured/**").requiresSecure() - .anyRequest().requiresInsecure(); + .anyRequest().requiresInsecure()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java index 1c463544f4..4eb4667b97 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpRequestCacheTests.java @@ -88,11 +88,10 @@ public class NamespaceHttpRequestCacheTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .requestCache() - .requestCache(requestCache()); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .requestCache((cache) -> cache + .requestCache(requestCache())); // @formatter:on return http.build(); } @@ -117,8 +116,8 @@ public class NamespaceHttpRequestCacheTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java index 1df9a4a4cf..8980c95c8c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java @@ -112,11 +112,10 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .exceptionHandling() - .accessDeniedPage("/AccessDeniedPageConfig"); + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .exceptionHandling((handling) -> handling + .accessDeniedPage("/AccessDeniedPageConfig")); return http.build(); // @formatter:on } @@ -152,11 +151,10 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .exceptionHandling() - .accessDeniedHandler(accessDeniedHandler()); + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .exceptionHandling((handling) -> handling + .accessDeniedHandler(accessDeniedHandler())); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java index 7085786c4e..5b6bbfd05c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpX509Tests.java @@ -54,6 +54,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -153,10 +154,9 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509(withDefaults()); // @formatter:on return http.build(); } @@ -182,11 +182,10 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509() - .authenticationDetailsSource(authenticationDetailsSource()); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509((x509) -> x509 + .authenticationDetailsSource(authenticationDetailsSource())); // @formatter:on return http.build(); } @@ -217,11 +216,10 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509() - .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509((x509) -> x509 + .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)")); // @formatter:on return http.build(); } @@ -247,11 +245,10 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509() - .x509PrincipalExtractor(this::extractCommonName); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509((x509) -> x509 + .x509PrincipalExtractor(this::extractCommonName)); // @formatter:on return http.build(); } @@ -282,11 +279,10 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509() - .userDetailsService((username) -> USER); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509((x509) -> x509 + .userDetailsService((username) -> USER)); // @formatter:on return http.build(); } @@ -312,11 +308,10 @@ public class NamespaceHttpX509Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .x509() - .authenticationUserDetailsService((authentication) -> USER); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .x509((x509) -> x509 + .authenticationUserDetailsService((authentication) -> USER)); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java index c55f865db8..a9434bef89 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java @@ -57,6 +57,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -287,12 +288,10 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -313,10 +312,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .rememberMeServices(REMEMBER_ME_SERVICES); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .rememberMeServices(REMEMBER_ME_SERVICES)); return http.build(); // @formatter:on } @@ -333,10 +331,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .authenticationSuccessHandler(SUCCESS_HANDLER); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .authenticationSuccessHandler(SUCCESS_HANDLER)); return http.build(); // @formatter:on } @@ -354,10 +351,9 @@ public class NamespaceRememberMeTests { http .securityMatcher(new AntPathRequestMatcher("/without-key/**")) .authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()) - .formLogin() - .loginProcessingUrl("/without-key/login") - .and() - .rememberMe(); + .formLogin((login) -> login + .loginProcessingUrl("/without-key/login")) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -367,13 +363,11 @@ public class NamespaceRememberMeTests { SecurityFilterChain keyFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .rememberMe() - .key("KeyConfig"); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .rememberMe((me) -> me + .key("KeyConfig")); return http.build(); // @formatter:on } @@ -392,10 +386,9 @@ public class NamespaceRememberMeTests { // tokenRepository.setDataSource(dataSource); // @formatter:off http - .formLogin() - .and() - .rememberMe() - .tokenRepository(TOKEN_REPOSITORY); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .tokenRepository(TOKEN_REPOSITORY)); return http.build(); // @formatter:on } @@ -410,13 +403,11 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .rememberMe() - .tokenValiditySeconds(314); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .rememberMe((me) -> me + .tokenValiditySeconds(314)); return http.build(); // @formatter:on } @@ -431,10 +422,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .useSecureCookie(true); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .useSecureCookie(true)); return http.build(); // @formatter:on } @@ -449,10 +439,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .rememberMeParameter("rememberMe"); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .rememberMeParameter("rememberMe")); return http.build(); // @formatter:on } @@ -467,10 +456,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .rememberMeCookieName("rememberMe"); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .rememberMeCookieName("rememberMe")); return http.build(); // @formatter:on } @@ -487,9 +475,8 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe(); + .formLogin(withDefaults()) + .rememberMe(withDefaults()); // @formatter:on return http.build(); } @@ -511,10 +498,9 @@ public class NamespaceRememberMeTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .rememberMe() - .userDetailsService(USERDETAILS_SERVICE); + .formLogin(withDefaults()) + .rememberMe((me) -> me + .userDetailsService(USERDETAILS_SERVICE)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java index 6f518db408..c06d54ede4 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceSessionManagementTests.java @@ -63,6 +63,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; @@ -287,18 +288,16 @@ public class NamespaceSessionManagementTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .and() - .sessionManagement() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic(withDefaults()) + .sessionManagement((management) -> management .invalidSessionUrl("/invalid-session") // session-management@invalid-session-url .sessionAuthenticationErrorUrl("/session-auth-error") // session-management@session-authentication-error-url .maximumSessions(1) // session-management/concurrency-control@max-sessions - .maxSessionsPreventsLogin(true) // session-management/concurrency-control@error-if-maximum-exceeded - .expiredUrl("/expired-session") // session-management/concurrency-control@expired-url - .sessionRegistry(sessionRegistry()); + .maxSessionsPreventsLogin(true) // session-management/concurrency-control@error-if-maximum-exceeded + .expiredUrl("/expired-session") // session-management/concurrency-control@expired-url + .sessionRegistry(sessionRegistry())); return http.build(); // session-management/concurrency-control@session-registry-ref // @formatter:on } @@ -320,8 +319,8 @@ public class NamespaceSessionManagementTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .invalidSessionStrategy(invalidSessionStrategy()); + .sessionManagement((management) -> management + .invalidSessionStrategy(invalidSessionStrategy())); return http.build(); // @formatter:on } @@ -343,10 +342,9 @@ public class NamespaceSessionManagementTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionAuthenticationStrategy(sessionAuthenticationStrategy()) // session-management@session-authentication-strategy-ref - .and() - .httpBasic(); + .sessionManagement((management) -> management + .sessionAuthenticationStrategy(sessionAuthenticationStrategy())) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -366,10 +364,9 @@ public class NamespaceSessionManagementTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy()) - .and() - .httpBasic(); + .sessionManagement((management) -> management + .sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy())) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -384,10 +381,9 @@ public class NamespaceSessionManagementTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .requireExplicitAuthenticationStrategy(false) - .and() - .httpBasic(); + .sessionManagement((management) -> management + .requireExplicitAuthenticationStrategy(false)) + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -403,9 +399,9 @@ public class NamespaceSessionManagementTests { // @formatter:off http .sessionManagement((sessions) -> sessions - .requireExplicitAuthenticationStrategy(false) + .requireExplicitAuthenticationStrategy(false) ) - .httpBasic(); + .httpBasic(withDefaults()); return http.build(); // @formatter:on } @@ -426,10 +422,10 @@ public class NamespaceSessionManagementTests { // @formatter:off http .sessionManagement((sessions) -> sessions - .sessionFixation().newSession() - .requireExplicitAuthenticationStrategy(false) + .sessionFixation().newSession() + .requireExplicitAuthenticationStrategy(false) ) - .httpBasic(); + .httpBasic(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java index 802735ec1a..1ff5905ca1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java @@ -100,12 +100,11 @@ public class PermitAllSupportTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login .loginPage("/xyz").permitAll() - .loginProcessingUrl("/abc?def").permitAll(); + .loginProcessingUrl("/abc?def").permitAll()); return http.build(); // @formatter:on } @@ -120,12 +119,11 @@ public class PermitAllSupportTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/xyz").permitAll() - .loginProcessingUrl("/abc?def").permitAll(); + .authorizeHttpRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login + .loginPage("/xyz").permitAll() + .loginProcessingUrl("/abc?def").permitAll()); return http.build(); // @formatter:on } @@ -140,15 +138,13 @@ public class PermitAllSupportTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .authorizeHttpRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/xyz").permitAll() - .loginProcessingUrl("/abc?def").permitAll(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .authorizeHttpRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin((login) -> login + .loginPage("/xyz").permitAll() + .loginProcessingUrl("/abc?def").permitAll()); return http.build(); // @formatter:on } @@ -163,8 +159,8 @@ public class PermitAllSupportTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .permitAll(); + .formLogin((login) -> login + .permitAll()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java index ce19e6aa20..8241948f98 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java @@ -32,6 +32,7 @@ import org.springframework.security.web.PortMapperImpl; import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; @@ -73,13 +74,11 @@ public class PortMapperConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requiresChannel() - .anyRequest().requiresSecure() - .and() - .portMapper() - .http(543).mapsTo(123) - .and() - .portMapper(); + .requiresChannel((channel) -> channel + .anyRequest().requiresSecure()) + .portMapper((mapper) -> mapper + .http(543).mapsTo(123)) + .portMapper(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java index e3cb83f76f..73be687d53 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java @@ -365,12 +365,10 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe(withDefaults()); // @formatter:on return http.build(); } @@ -398,8 +396,8 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .rememberMe() - .userDetailsService(new AuthenticationManagerBuilder(this.objectPostProcessor).getDefaultUserDetailsService()); + .rememberMe((me) -> me + .userDetailsService(new AuthenticationManagerBuilder(this.objectPostProcessor).getDefaultUserDetailsService())); // @formatter:on return http.build(); } @@ -435,12 +433,10 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .rememberMe() - .userDetailsService(userDetailsService) - .and() - .rememberMe(); + .httpBasic(withDefaults()) + .rememberMe((me) -> me + .userDetailsService(userDetailsService)) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -489,12 +485,10 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe(); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe(withDefaults()); return http.build(); // @formatter:on } @@ -539,13 +533,11 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe() - .rememberMeCookieDomain("spring.io"); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe((me) -> me + .rememberMeCookieDomain("spring.io")); return http.build(); // @formatter:on } @@ -595,15 +587,13 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe() + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe((me) -> me .rememberMeCookieName("SPRING_COOKIE_DOMAIN") .rememberMeCookieDomain("spring.io") - .rememberMeServices(REMEMBER_ME); + .rememberMeServices(REMEMBER_ME)); return http.build(); // @formatter:on } @@ -627,13 +617,11 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().hasRole("USER") - .and() - .formLogin() - .and() - .rememberMe() - .rememberMeServices(new TokenBasedRememberMeServices("key", userDetailsService())); + .authorizeRequests((requests) -> requests + .anyRequest().hasRole("USER")) + .formLogin(withDefaults()) + .rememberMe((me) -> me + .rememberMeServices(new TokenBasedRememberMeServices("key", userDetailsService()))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java index e6a597e0a8..f22d69e1a3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java @@ -328,7 +328,7 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requestCache(); + .requestCache(withDefaults()); return http.build(); // @formatter:on } @@ -359,10 +359,9 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requestCache() - .requestCache(requestCache) - .and() - .requestCache(); + .requestCache((cache) -> cache + .requestCache(requestCache)) + .requestCache(withDefaults()); return http.build(); // @formatter:on } @@ -377,10 +376,9 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java index 066c491701..f8b18381be 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java @@ -78,14 +78,12 @@ public class RequestMatcherConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers() - .requestMatchers(new AntPathRequestMatcher("/api/**")) - .and() - .securityMatchers() - .requestMatchers(new AntPathRequestMatcher("/oauth/**")) - .and() - .authorizeRequests() - .anyRequest().denyAll(); + .securityMatchers((security) -> security + .requestMatchers(new AntPathRequestMatcher("/api/**"))) + .securityMatchers((security) -> security + .requestMatchers(new AntPathRequestMatcher("/oauth/**"))) + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java index 31c6fbfc66..ad14a2c5d1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java @@ -152,7 +152,7 @@ public class SecurityContextConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityContext(); + .securityContext(withDefaults()); return http.build(); // @formatter:on } @@ -183,10 +183,9 @@ public class SecurityContextConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityContext() - .securityContextRepository(SCR) - .and() - .securityContext(); + .securityContext((context) -> context + .securityContextRepository(SCR)) + .securityContext(withDefaults()); return http.build(); // @formatter:on } @@ -203,14 +202,11 @@ public class SecurityContextConfigurerTests { // @formatter:off http .addFilter(new WebAsyncManagerIntegrationFilter()) - .anonymous() - .and() - .securityContext() - .and() - .authorizeRequests() - .anyRequest().permitAll() - .and() - .httpBasic(); + .anonymous(withDefaults()) + .securityContext(withDefaults()) + .authorizeRequests((requests) -> requests + .anyRequest().permitAll()) + .httpBasic(withDefaults()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java index 9c1a47cf90..f1df48be8c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java @@ -224,7 +224,7 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .servletApi(); + .servletApi(withDefaults()); return http.build(); // @formatter:on } @@ -286,13 +286,11 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(ENTRYPOINT) - .and() - .formLogin(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .exceptionHandling((handling) -> handling + .authenticationEntryPoint(ENTRYPOINT)) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -312,10 +310,9 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .servletApi() - .rolePrefix("PERMISSION_") - .and() - .servletApi(); + .servletApi((api) -> api + .rolePrefix("PERMISSION_")) + .servletApi(withDefaults()); return http.build(); // @formatter:on } @@ -392,8 +389,8 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .servletApi().and() - .logout(); + .servletApi(withDefaults()) + .logout(withDefaults()); return http.build(); // @formatter:on } @@ -408,7 +405,7 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf().disable(); + .csrf((csrf) -> csrf.disable()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java index e5e129197d..cd32887961 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerServlet31Tests.java @@ -45,6 +45,7 @@ import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -122,9 +123,8 @@ public class SessionManagementConfigurerServlet31Tests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .sessionManagement(); + .formLogin(withDefaults()) + .sessionManagement(withDefaults()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionAuthenticationStrategyTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionAuthenticationStrategyTests.java index 045c1089e1..75feb75189 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionAuthenticationStrategyTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionAuthenticationStrategyTests.java @@ -39,6 +39,7 @@ import org.springframework.test.web.servlet.MockMvc; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; /** @@ -72,10 +73,9 @@ public class SessionManagementConfigurerSessionAuthenticationStrategyTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .sessionManagement() - .sessionAuthenticationStrategy(customSessionAuthenticationStrategy); + .formLogin(withDefaults()) + .sessionManagement((management) -> management + .sessionAuthenticationStrategy(customSessionAuthenticationStrategy)); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java index c7305f9834..50eadd28ed 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerSessionCreationPolicyTests.java @@ -93,7 +93,7 @@ public class SessionManagementConfigurerSessionCreationPolicyTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionManagement((management) -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // @formatter:on http.setSharedObject(SessionCreationPolicy.class, SessionCreationPolicy.ALWAYS); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java index bca300ec52..04ce689e96 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java @@ -551,11 +551,10 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requestCache() - .requestCache(REQUEST_CACHE) - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .requestCache((cache) -> cache + .requestCache(REQUEST_CACHE)) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); // @formatter:on } @@ -572,11 +571,10 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityContext() - .securityContextRepository(SECURITY_CONTEXT_REPO) - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .securityContext((context) -> context + .securityContextRepository(SECURITY_CONTEXT_REPO)) + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); // @formatter:on } @@ -591,10 +589,9 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .sessionManagement(); + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .sessionManagement(withDefaults()); return http.build(); // @formatter:on } @@ -609,11 +606,10 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic() - .and() - .sessionManagement() + .httpBasic(withDefaults()) + .sessionManagement((management) -> management .sessionFixation().none() - .maximumSessions(1); + .maximumSessions(1)); // @formatter:on return http.build(); } @@ -658,11 +654,10 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .formLogin() - .and() - .sessionManagement() + .formLogin(withDefaults()) + .sessionManagement((management) -> management .maximumSessions(1) - .maxSessionsPreventsLogin(true); + .maxSessionsPreventsLogin(true)); // @formatter:on return http.build(); } @@ -766,8 +761,8 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .maximumSessions(1); + .sessionManagement((management) -> management + .maximumSessions(1)); return http.build(); // @formatter:on } @@ -818,8 +813,8 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .maximumSessions(1); + .sessionManagement((management) -> management + .maximumSessions(1)); return http.build(); // @formatter:on } @@ -843,8 +838,8 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .maximumSessions(1); + .sessionManagement((management) -> management + .maximumSessions(1)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTransientAuthenticationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTransientAuthenticationTests.java index bef7862820..0011e89af8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTransientAuthenticationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTransientAuthenticationTests.java @@ -72,7 +72,7 @@ public class SessionManagementConfigurerTransientAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf().disable() + .csrf((csrf) -> csrf.disable()) .authenticationProvider(new TransientAuthenticationProvider()); // @formatter:on return http.build(); @@ -88,7 +88,7 @@ public class SessionManagementConfigurerTransientAuthenticationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS); + .sessionManagement((management) -> management.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java index fe93d6bb64..d0728428dc 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java @@ -49,6 +49,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -135,9 +136,9 @@ public class UrlAuthorizationConfigurerTests { HandlerMappingIntrospector introspector) throws Exception { // @formatter:off http - .httpBasic().and() + .httpBasic(withDefaults()) .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(new MvcRequestMatcher(introspector, "/path")).hasRole("ADMIN"); + .requestMatchers(new MvcRequestMatcher(introspector, "/path")).hasRole("ADMIN"); // @formatter:on return http.build(); } @@ -171,9 +172,9 @@ public class UrlAuthorizationConfigurerTests { mvcRequestMatcher.setServletPath("/spring"); // @formatter:off http - .httpBasic().and() + .httpBasic(withDefaults()) .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(mvcRequestMatcher).hasRole("ADMIN"); + .requestMatchers(mvcRequestMatcher).hasRole("ADMIN"); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java index 9cbf6617b9..7f0af95555 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationsTests.java @@ -141,13 +141,13 @@ public class UrlAuthorizationsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/role-user-authority").hasAnyAuthority("ROLE_USER") .requestMatchers("/role-admin-authority").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/role-user-admin-authority").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN") .requestMatchers("/role-user").hasAnyRole("USER") .requestMatchers("/role-admin").hasAnyRole("ADMIN") - .requestMatchers("/role-user-admin").hasAnyRole("USER", "ADMIN"); + .requestMatchers("/role-user-admin").hasAnyRole("USER", "ADMIN")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java index 63a3a963df..7293eb32fa 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java @@ -199,7 +199,7 @@ public class X509ConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .x509(); + .x509(withDefaults()); return http.build(); // @formatter:on } @@ -228,10 +228,9 @@ public class X509ConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .x509() - .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)") - .and() - .x509(); + .x509((x509) -> x509 + .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)")) + .x509(withDefaults()); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java index 42d6ab7103..15f011de74 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java @@ -354,17 +354,15 @@ public class OAuth2ClientConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .requestCache() - .requestCache(requestCache) - .and() - .oauth2Client() - .authorizationCodeGrant() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .requestCache((cache) -> cache + .requestCache(requestCache)) + .oauth2Client((client) -> client + .authorizationCodeGrant((code) -> code .authorizationRequestResolver(authorizationRequestResolver) .authorizationRedirectStrategy(authorizationRedirectStrategy) - .accessTokenResponseClient(accessTokenResponseClient); + .accessTokenResponseClient(accessTokenResponseClient))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 9895beaded..980c7c5995 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -44,6 +44,7 @@ import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -118,6 +119,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; +import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; @@ -780,9 +782,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)); + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))); // @formatter:on return super.configureFilterChain(http); } @@ -805,10 +807,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() - .clientRegistrationRepository(this.clientRegistrationRepository) - .and() - .formLogin(); + .oauth2Login((login) -> login + .clientRegistrationRepository(this.clientRegistrationRepository)) + .formLogin(withDefaults()); // @formatter:on return super.configureFilterChain(http); } @@ -850,11 +851,11 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) - .userInfoEndpoint() - .userAuthoritiesMapper(createGrantedAuthoritiesMapper()); + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) + .userInfoEndpoint((info) -> info + .userAuthoritiesMapper(createGrantedAuthoritiesMapper()))); // @formatter:on return super.configureFilterChain(http); } @@ -869,7 +870,7 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login(); + .oauth2Login(withDefaults()); // @formatter:on return super.configureFilterChain(http); } @@ -894,15 +895,13 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .securityContext() - .securityContextRepository(securityContextRepository()) - .and() - .oauth2Login() - .tokenEndpoint() - .accessTokenResponseClient(createOauth2AccessTokenResponseClient()); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .securityContext((context) -> context + .securityContextRepository(securityContextRepository())) + .oauth2Login((login) -> login + .tokenEndpoint((token) -> token + .accessTokenResponseClient(createOauth2AccessTokenResponseClient()))); return http.build(); // @formatter:on } @@ -947,10 +946,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) - .loginProcessingUrl("/login/oauth2/*"); + .loginProcessingUrl("/login/oauth2/*")); // @formatter:on return super.configureFilterChain(http); } @@ -970,10 +969,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository(this.clientRegistrationRepository) - .authorizationEndpoint() - .authorizationRequestResolver(this.resolver); + .authorizationEndpoint((authorize) -> authorize + .authorizationRequestResolver(this.resolver))); // @formatter:on return super.configureFilterChain(http); } @@ -991,9 +990,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository(this.clientRegistrationRepository) - .authorizationEndpoint(); + .authorizationEndpoint(Customizer.withDefaults())); // @formatter:on return super.configureFilterChain(http); } @@ -1106,10 +1105,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository( - GOOGLE_CLIENT_REGISTRATION, GITHUB_CLIENT_REGISTRATION)); + new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION, GITHUB_CLIENT_REGISTRATION))); // @formatter:on return super.configureFilterChain(http); } @@ -1124,10 +1123,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository( - GOOGLE_CLIENT_REGISTRATION, CLIENT_CREDENTIALS_REGISTRATION)); + new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION, CLIENT_CREDENTIALS_REGISTRATION))); // @formatter:on return super.configureFilterChain(http); } @@ -1142,10 +1141,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) - .loginPage("/custom-login"); + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) + .loginPage("/custom-login")); // @formatter:on return super.configureFilterChain(http); } @@ -1180,8 +1179,8 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout() - .logoutSuccessHandler(oidcLogoutSuccessHandler()); + .logout((logout) -> logout + .logoutSuccessHandler(oidcLogoutSuccessHandler())); // @formatter:on return super.configureFilterChain(http); } @@ -1209,11 +1208,10 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) - .and() - .httpBasic(); + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))) + .httpBasic(withDefaults()); // @formatter:on return super.configureFilterChain(http); } @@ -1254,14 +1252,13 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login() + .oauth2Login((login) -> login .clientRegistrationRepository( - new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) - .and() - .exceptionHandling() + new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))) + .exceptionHandling((handling) -> handling .defaultAuthenticationEntryPointFor( - new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), - new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); + new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), + new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"))); // @formatter:on return super.configureFilterChain(http); } @@ -1312,19 +1309,16 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .securityContext() - .securityContextRepository(securityContextRepository()) - .and() - .oauth2Login() - .tokenEndpoint() - .accessTokenResponseClient(createOauth2AccessTokenResponseClient()) - .and() - .userInfoEndpoint() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .securityContext((context) -> context + .securityContextRepository(securityContextRepository())) + .oauth2Login((login) -> login + .tokenEndpoint((token) -> token + .accessTokenResponseClient(createOauth2AccessTokenResponseClient())) + .userInfoEndpoint((info) -> info .userService(createOauth2UserService()) - .oidcUserService(createOidcUserService()); + .oidcUserService(createOidcUserService()))); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index b88ed1a1c7..c7c31aa5e4 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -82,10 +82,10 @@ import org.springframework.security.authentication.AuthenticationManagerResolver import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.config.Customizer; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; @@ -163,7 +163,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; @@ -815,15 +814,16 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getJwtDecoderWhenConfiguredWithDecoderAndJwkSetUriThenLastOneWins() { ApplicationContext context = mock(ApplicationContext.class); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); JwtDecoder decoder = mock(JwtDecoder.class); - jwtConfigurer.jwkSetUri(JWK_SET_URI); - jwtConfigurer.decoder(decoder); - assertThat(jwtConfigurer.getJwtDecoder()).isEqualTo(decoder); - jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.decoder(decoder); - jwtConfigurer.jwkSetUri(JWK_SET_URI); - assertThat(jwtConfigurer.getJwtDecoder()).isInstanceOf(NimbusJwtDecoder.class); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.jwkSetUri(JWK_SET_URI); + jwt.decoder(decoder); + assertThat(jwt.getJwtDecoder()).isEqualTo(decoder); + }); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.decoder(decoder).jwkSetUri(JWK_SET_URI); + assertThat(jwt.getJwtDecoder()).isInstanceOf(NimbusJwtDecoder.class); + }); } @Test @@ -832,9 +832,10 @@ public class OAuth2ResourceServerConfigurerTests { JwtDecoder decoder = mock(JwtDecoder.class); ApplicationContext context = mock(ApplicationContext.class); given(context.getBean(JwtDecoder.class)).willReturn(decoderBean); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.decoder(decoder); - assertThat(jwtConfigurer.getJwtDecoder()).isEqualTo(decoder); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.decoder(decoder); + assertThat(jwt.getJwtDecoder()).isEqualTo(decoder); + }); } @Test @@ -842,10 +843,11 @@ public class OAuth2ResourceServerConfigurerTests { JwtDecoder decoder = mock(JwtDecoder.class); ApplicationContext context = mock(ApplicationContext.class); given(context.getBean(JwtDecoder.class)).willReturn(decoder); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.jwkSetUri(JWK_SET_URI); - assertThat(jwtConfigurer.getJwtDecoder()).isNotEqualTo(decoder); - assertThat(jwtConfigurer.getJwtDecoder()).isInstanceOf(NimbusJwtDecoder.class); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.jwkSetUri(JWK_SET_URI); + assertThat(jwt.getJwtDecoder()).isNotEqualTo(decoder); + assertThat(jwt.getJwtDecoder()).isInstanceOf(NimbusJwtDecoder.class); + }); } @Test @@ -856,9 +858,10 @@ public class OAuth2ResourceServerConfigurerTests { context.registerBean("decoderOne", JwtDecoder.class, () -> decoderBean); context.registerBean("decoderTwo", JwtDecoder.class, () -> decoderBean); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.decoder(decoder); - assertThat(jwtConfigurer.getJwtDecoder()).isEqualTo(decoder); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.decoder(decoder); + assertThat(jwt.getJwtDecoder()).isEqualTo(decoder); + }); } @Test @@ -868,8 +871,9 @@ public class OAuth2ResourceServerConfigurerTests { context.registerBean("decoderOne", JwtDecoder.class, () -> decoder); context.registerBean("decoderTwo", JwtDecoder.class, () -> decoder); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(jwtConfigurer::getJwtDecoder); + new OAuth2ResourceServerConfigurer(context) + .jwt((jwt) -> assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) + .isThrownBy(jwt::getJwtDecoder)); } @Test @@ -1152,19 +1156,19 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getIntrospectionClientWhenConfiguredWithClientAndIntrospectionUriThenLastOneWins() { ApplicationContext context = mock(ApplicationContext.class); - OAuth2ResourceServerConfigurer.OpaqueTokenConfigurer opaqueTokenConfigurer = new OAuth2ResourceServerConfigurer( - context) - .opaqueToken(); OpaqueTokenIntrospector client = mock(OpaqueTokenIntrospector.class); - opaqueTokenConfigurer.introspectionUri(INTROSPECTION_URI); - opaqueTokenConfigurer.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); - opaqueTokenConfigurer.introspector(client); - assertThat(opaqueTokenConfigurer.getIntrospector()).isEqualTo(client); - opaqueTokenConfigurer = new OAuth2ResourceServerConfigurer(context).opaqueToken(); - opaqueTokenConfigurer.introspector(client); - opaqueTokenConfigurer.introspectionUri(INTROSPECTION_URI); - opaqueTokenConfigurer.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); - assertThat(opaqueTokenConfigurer.getIntrospector()).isNotSameAs(client); + new OAuth2ResourceServerConfigurer(context).opaqueToken((opaqueToken) -> { + opaqueToken.introspectionUri(INTROSPECTION_URI); + opaqueToken.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); + opaqueToken.introspector(client); + assertThat(opaqueToken.getIntrospector()).isEqualTo(client); + }); + new OAuth2ResourceServerConfigurer(context).opaqueToken((opaqueToken) -> { + opaqueToken.introspector(client); + opaqueToken.introspectionUri(INTROSPECTION_URI); + opaqueToken.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); + assertThat(opaqueToken.getIntrospector()).isNotSameAs(client); + }); } @Test @@ -1172,11 +1176,11 @@ public class OAuth2ResourceServerConfigurerTests { GenericApplicationContext context = new GenericApplicationContext(); registerMockBean(context, "introspectionClientOne", OpaqueTokenIntrospector.class); registerMockBean(context, "introspectionClientTwo", OpaqueTokenIntrospector.class); - OAuth2ResourceServerConfigurer.OpaqueTokenConfigurer opaqueToken = new OAuth2ResourceServerConfigurer(context) - .opaqueToken(); - opaqueToken.introspectionUri(INTROSPECTION_URI); - opaqueToken.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); - assertThat(opaqueToken.getIntrospector()).isNotNull(); + new OAuth2ResourceServerConfigurer(context).opaqueToken((opaqueToken) -> { + opaqueToken.introspectionUri(INTROSPECTION_URI); + opaqueToken.introspectionClientCredentials(CLIENT_ID, CLIENT_SECRET); + assertThat(opaqueToken.getIntrospector()).isNotNull(); + }); } @Test @@ -1263,17 +1267,16 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getAuthenticationManagerWhenConfiguredAuthenticationManagerThenTakesPrecedence() { ApplicationContext context = mock(ApplicationContext.class); - HttpSecurityBuilder http = mock(HttpSecurityBuilder.class); - OAuth2ResourceServerConfigurer oauth2ResourceServer = new OAuth2ResourceServerConfigurer(context); + OAuth2ResourceServerConfigurer oauth2ResourceServer = new OAuth2ResourceServerConfigurer<>( + context); AuthenticationManager authenticationManager = mock(AuthenticationManager.class); - oauth2ResourceServer.jwt().authenticationManager(authenticationManager).decoder(mock(JwtDecoder.class)); - assertThat(oauth2ResourceServer.getAuthenticationManager(http)).isSameAs(authenticationManager); - oauth2ResourceServer = new OAuth2ResourceServerConfigurer(context); - oauth2ResourceServer.opaqueToken() - .authenticationManager(authenticationManager) - .introspector(mock(OpaqueTokenIntrospector.class)); - assertThat(oauth2ResourceServer.getAuthenticationManager(http)).isSameAs(authenticationManager); - verify(http, never()).authenticationProvider(any(AuthenticationProvider.class)); + oauth2ResourceServer + .jwt((jwt) -> jwt.authenticationManager(authenticationManager).decoder(mock(JwtDecoder.class))); + assertThat(oauth2ResourceServer.getAuthenticationManager(null)).isSameAs(authenticationManager); + oauth2ResourceServer = new OAuth2ResourceServerConfigurer<>(context); + oauth2ResourceServer.opaqueToken((opaqueToken) -> opaqueToken.authenticationManager(authenticationManager) + .introspector(mock(OpaqueTokenIntrospector.class))); + assertThat(oauth2ResourceServer.getAuthenticationManager(null)).isSameAs(authenticationManager); } @Test @@ -1343,8 +1346,9 @@ public class OAuth2ResourceServerConfigurerTests { @Test public void getJwtAuthenticationConverterWhenNoConverterSpecifiedThenTheDefaultIsUsed() { ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - assertThat(jwtConfigurer.getJwtAuthenticationConverter()).isInstanceOf(JwtAuthenticationConverter.class); + new OAuth2ResourceServerConfigurer(context) + .jwt((jwt) -> assertThat(jwt.getJwtAuthenticationConverter()) + .isInstanceOf(JwtAuthenticationConverter.class)); } @Test @@ -1353,8 +1357,8 @@ public class OAuth2ResourceServerConfigurerTests { GenericWebApplicationContext context = new GenericWebApplicationContext(); context.registerBean(JwtAuthenticationConverter.class, () -> converterBean); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - assertThat(jwtConfigurer.getJwtAuthenticationConverter()).isEqualTo(converterBean); + new OAuth2ResourceServerConfigurer(context) + .jwt((jwt) -> assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(converterBean)); } @Test @@ -1364,9 +1368,10 @@ public class OAuth2ResourceServerConfigurerTests { GenericWebApplicationContext context = new GenericWebApplicationContext(); context.registerBean(JwtAuthenticationConverter.class, () -> converterBean); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.jwtAuthenticationConverter(converter); - assertThat(jwtConfigurer.getJwtAuthenticationConverter()).isEqualTo(converter); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.jwtAuthenticationConverter(converter); + assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(converter); + }); } @Test @@ -1377,9 +1382,10 @@ public class OAuth2ResourceServerConfigurerTests { context.registerBean("converterOne", JwtAuthenticationConverter.class, () -> converterBean); context.registerBean("converterTwo", JwtAuthenticationConverter.class, () -> converterBean); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - jwtConfigurer.jwtAuthenticationConverter(converter); - assertThat(jwtConfigurer.getJwtAuthenticationConverter()).isEqualTo(converter); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + jwt.jwtAuthenticationConverter(converter); + assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(converter); + }); } @Test @@ -1389,9 +1395,10 @@ public class OAuth2ResourceServerConfigurerTests { context.registerBean("converterOne", JwtAuthenticationConverter.class, () -> converterBean); context.registerBean("converterTwo", JwtAuthenticationConverter.class, () -> converterBean); this.spring.context(context).autowire(); - OAuth2ResourceServerConfigurer.JwtConfigurer jwtConfigurer = new OAuth2ResourceServerConfigurer(context).jwt(); - assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) - .isThrownBy(jwtConfigurer::getJwtAuthenticationConverter); + new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { + assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) + .isThrownBy(jwt::getJwtAuthenticationConverter); + }); } @Test @@ -1550,12 +1557,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1600,14 +1606,12 @@ public class OAuth2ResourceServerConfigurerTests { DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver(); defaultBearerTokenResolver.setAllowUriQueryParameter(true); http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server .bearerTokenResolver(defaultBearerTokenResolver) - .jwt() - .jwkSetUri(this.jwkSetUri); + .jwt((jwt) -> jwt.jwkSetUri(this.jwkSetUri))); return http.build(); // @formatter:on } @@ -1656,14 +1660,12 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") - .anyRequest().authenticated() - .and() - .csrf().disable() - .oauth2ResourceServer() - .jwt() - .jwkSetUri(this.jwkSetUri); + .anyRequest().authenticated()) + .csrf((csrf) -> csrf.disable()) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.jwkSetUri(this.jwkSetUri))); return http.build(); // @formatter:on } @@ -1678,12 +1680,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .anonymous().disable() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .anonymous((anonymous) -> anonymous.disable()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1699,11 +1700,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1718,10 +1718,9 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer(withDefaults()); return http.build(); // @formatter:on } @@ -1736,12 +1735,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server .authenticationEntryPoint(authenticationEntryPoint()) - .jwt(); + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1762,12 +1760,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .oauth2ResourceServer() + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .oauth2ResourceServer((server) -> server .accessDeniedHandler(accessDeniedHandler()) - .jwt(); + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1788,16 +1785,13 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().denyAll() - .and() - .exceptionHandling() - .defaultAccessDeniedHandlerFor(new AccessDeniedHandlerImpl(), (request) -> false) - .and() - .httpBasic() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().denyAll()) + .exceptionHandling((handling) -> handling + .defaultAccessDeniedHandlerFor(new AccessDeniedHandlerImpl(), (request) -> false)) + .httpBasic(withDefaults()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1826,12 +1820,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt() - .jwtAuthenticationConverter(getJwtAuthenticationConverter()); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt + .jwtAuthenticationConverter(getJwtAuthenticationConverter()))); return http.build(); // @formatter:on } @@ -1851,12 +1844,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .requestMatchers("/requires-read-scope").access("hasAuthority('message:read')") - .and() - .oauth2ResourceServer() - .jwt() - .jwtAuthenticationConverter(getJwtAuthenticationConverter()); + .authorizeRequests((requests) -> requests + .requestMatchers("/requires-read-scope").access("hasAuthority('message:read')")) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt + .jwtAuthenticationConverter(getJwtAuthenticationConverter()))); return http.build(); // @formatter:on } @@ -1878,13 +1870,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .httpBasic() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .httpBasic(withDefaults()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1911,13 +1901,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .formLogin(withDefaults()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1957,11 +1945,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // missing key configuration, e.g. jwkSetUri // @formatter:on } @@ -1976,11 +1963,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) - .and() - .oauth2ResourceServer() - .jwt(); + .sessionManagement((management) -> management + .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -1995,12 +1981,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server .bearerTokenResolver(allowRequestBody()) - .jwt(); + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2021,11 +2006,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2047,11 +2031,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2115,12 +2098,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt() - .decoder(decoder()); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.decoder(decoder()))); return http.build(); // @formatter:on } @@ -2170,11 +2151,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2194,12 +2174,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt() - .authenticationManager(authenticationProvider()::authenticate); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt + .authenticationManager(authenticationProvider()::authenticate))); return http.build(); // @formatter:on } @@ -2260,8 +2239,8 @@ public class OAuth2ResourceServerConfigurerTests { this.jwtDecoder.setJwtValidator(this.jwtValidator); // @formatter:off http - .oauth2ResourceServer() - .jwt(); + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2288,8 +2267,8 @@ public class OAuth2ResourceServerConfigurerTests { this.jwtDecoder.setJwtValidator(jwtValidator); // @formatter:off http - .oauth2ResourceServer() - .jwt(); + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2312,8 +2291,8 @@ public class OAuth2ResourceServerConfigurerTests { this.jwtDecoder.setJwtValidator(jwtValidator); // @formatter:off http - .oauth2ResourceServer() - .jwt(); + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); } } @@ -2333,11 +2312,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2359,11 +2337,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2389,12 +2366,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read") - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .opaqueToken(); + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .opaqueToken(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2433,12 +2409,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .opaqueToken() - .authenticationManager(authenticationProvider()::authenticate); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken + .authenticationManager(authenticationProvider()::authenticate))); return http.build(); // @formatter:on } @@ -2523,10 +2498,9 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2ResourceServer() - .jwt() - .and() - .opaqueToken(); + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults()) + .opaqueToken(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2541,12 +2515,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .opaqueToken() - .introspectionUri("https://idp.example.com"); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken + .introspectionUri("https://idp.example.com"))); return http.build(); // missing credentials // @formatter:on } @@ -2561,11 +2534,10 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .jwt(); + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2605,9 +2577,8 @@ public class OAuth2ResourceServerConfigurerTests { issuerOne, issuerTwo); // @formatter:off http - .oauth2ResourceServer() - .authenticationManagerResolver(authenticationManagerResolver) - .and() + .oauth2ResourceServer((server) -> server + .authenticationManagerResolver(authenticationManagerResolver)) .anonymous(AbstractHttpConfigurer::disable); return http.build(); // @formatter:on @@ -2623,12 +2594,11 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() + .authorizeRequests((requests) -> requests + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server .authenticationManagerResolver(mock(AuthenticationManagerResolver.class)) - .opaqueToken(); + .opaqueToken(Customizer.withDefaults())); return http.build(); // @formatter:on } @@ -2644,13 +2614,12 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() + .authorizeRequests((requests) -> requests .requestMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read") - .anyRequest().authenticated() - .and() - .oauth2ResourceServer() - .opaqueToken() - .authenticationConverter(authenticationConverter()); + .anyRequest().authenticated()) + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken + .authenticationConverter(authenticationConverter()))); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java index 4d262c91d5..8db919dd72 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java @@ -486,7 +486,7 @@ public class Saml2LoginConfigurerTests { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.saml2Login().authenticationManager(getAuthenticationManagerMock("ROLE_AUTH_MANAGER")); + http.saml2Login((login) -> login.authenticationManager(getAuthenticationManagerMock("ROLE_AUTH_MANAGER"))); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java index bb3a3dbfb8..36c2d0895c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurerTests.java @@ -591,7 +591,7 @@ public class Saml2LogoutConfigurerTests { .logout((logout) -> logout.logoutSuccessHandler(this.mockLogoutSuccessHandler)) .saml2Login(withDefaults()) .saml2Logout(withDefaults()) - .csrf().disable(); + .csrf((csrf) -> csrf.disable()); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/core/GrantedAuthorityDefaultsJcTests.java b/config/src/test/java/org/springframework/security/config/core/GrantedAuthorityDefaultsJcTests.java index 05553ba0ab..b15337e7b3 100644 --- a/config/src/test/java/org/springframework/security/config/core/GrantedAuthorityDefaultsJcTests.java +++ b/config/src/test/java/org/springframework/security/config/core/GrantedAuthorityDefaultsJcTests.java @@ -165,8 +165,8 @@ public class GrantedAuthorityDefaultsJcTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests() - .anyRequest().access("hasRole('USER')"); + .authorizeRequests((requests) -> requests + .anyRequest().access("hasRole('USER')")); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java index d5460316da..1c2ca465fa 100644 --- a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java +++ b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomConfigurer.java @@ -43,16 +43,16 @@ public class CustomConfigurer extends SecurityConfigurerAdapter requests .requestMatchers(new AntPathRequestMatcher(this.permitAllPattern)).permitAll() - .anyRequest().authenticated(); + .anyRequest().authenticated()); // @formatter:on if (http.getConfigurer(FormLoginConfigurer.class) == null) { // only apply if formLogin() was not invoked by the user // @formatter:off http - .formLogin() - .loginPage(this.loginPage); + .formLogin((login) -> login + .loginPage(this.loginPage)); // @formatter:on } } diff --git a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomHttpSecurityConfigurerTests.java b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomHttpSecurityConfigurerTests.java index 077a530388..c47bf68b6e 100644 --- a/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomHttpSecurityConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/http/customconfigurer/CustomHttpSecurityConfigurerTests.java @@ -32,6 +32,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.FilterChainProxy; @@ -144,11 +145,10 @@ public class CustomHttpSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .apply(CustomConfigurer.customConfigurer()) - .and() - .csrf().disable() - .formLogin() - .loginPage("/other"); + .with(CustomConfigurer.customConfigurer(), Customizer.withDefaults()) + .csrf((csrf) -> csrf.disable()) + .formLogin((login) -> login + .loginPage("/other")); return http.build(); // @formatter:on } diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/CorsDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/CorsDslTests.kt index 67caafa812..b176c6bad8 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/CorsDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/CorsDslTests.kt @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.HttpHeaders +import org.springframework.security.config.Customizer.withDefaults import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.test.SpringTestContext @@ -128,7 +129,7 @@ class CorsDslTests { open class CorsDisabledConfig { @Bean open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http.cors() + http.cors(withDefaults()) http { cors { disable() diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt index 3d35b8c2fe..71d7fd9e2c 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt @@ -25,6 +25,7 @@ import org.junit.jupiter.api.extension.ExtendWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.security.config.Customizer.withDefaults import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity @@ -127,7 +128,7 @@ class FormLoginDslTests { open class DisabledConfig { @Bean open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http.formLogin() + http.formLogin(withDefaults()) http { formLogin { disable() From 45a1447e9b5b06fa5a75078c42442d667055b0d9 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:06:54 -0600 Subject: [PATCH 401/504] Use HttpSecurity Lambda DSL in JavaDoc Issue gh-13067 --- .../annotation/web/builders/HttpSecurity.java | 47 ++++++++++--------- .../web/configuration/EnableWebSecurity.java | 5 +- .../web/configurers/AnonymousConfigurer.java | 3 +- .../ChannelSecurityConfigurer.java | 4 +- .../web/configurers/CorsConfigurer.java | 3 +- .../web/configurers/CsrfConfigurer.java | 15 +++--- .../ExceptionHandlingConfigurer.java | 3 +- .../ExpressionUrlAuthorizationConfigurer.java | 7 ++- .../web/configurers/FormLoginConfigurer.java | 3 +- .../web/configurers/HeadersConfigurer.java | 4 +- .../web/configurers/HttpBasicConfigurer.java | 3 +- .../web/configurers/JeeConfigurer.java | 3 +- .../web/configurers/LogoutConfigurer.java | 5 +- .../SecurityContextConfigurer.java | 3 +- .../web/configurers/ServletApiConfigurer.java | 3 +- .../SessionManagementConfigurer.java | 4 +- .../web/configurers/X509Configurer.java | 3 +- .../oauth2/client/OAuth2LoginConfigurer.java | 4 +- .../saml2/Saml2LoginConfigurer.java | 3 +- .../saml2/Saml2LogoutConfigurer.java | 6 ++- 20 files changed, 81 insertions(+), 50 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index ed84d98016..e441b92504 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -103,6 +103,8 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; +import static org.springframework.security.config.Customizer.withDefaults; + /** * A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the * namespace configuration. It allows configuring web based security for specific http @@ -219,8 +221,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder * @Configuration @@ -266,8 +268,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder @@ -331,7 +333,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configurations * * Accepting the default provided by {@link EnableWebSecurity} or only invoking - * {@link #headers()} without invoking additional methods on it, is the equivalent of: + * {@link #headers(Customizer)} without invoking additional methods on it, is the + * equivalent of: * *

 	 * @Configuration
@@ -372,9 +375,9 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder
 	 * @Configuration
@@ -397,7 +400,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder
 	 * @Configuration
@@ -615,9 +618,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration
 	 *
@@ -657,7 +661,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation
 	 * for more details.
-	 * @see #requiresChannel()
+	 * @see #requiresChannel(withDefaults())
 	 */
 	@Deprecated(since = "6.1", forRemoval = true)
 	public PortMapperConfigurer portMapper() throws Exception {
@@ -669,9 +673,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration
 	 *
@@ -714,7 +719,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder> portMapperCustomizer)
 			throws Exception {
@@ -1776,7 +1781,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Custom Configuration
@@ -1827,8 +1832,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Custom Configuration
 	 *
@@ -2499,7 +2504,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderrequired and must be
 	 * registered with the {@link ApplicationContext} or configured via
-	 * {@link #saml2Login()}.
+ * {@link #saml2Login(withDefaults())}.
*
* * The default configuration provides an auto-generated logout endpoint at diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java index 84706ebae4..49ac91307d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/EnableWebSecurity.java @@ -46,8 +46,9 @@ import org.springframework.security.web.SecurityFilterChain; * * @Bean * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - * http.authorizeHttpRequests().requestMatchers("/public/**").permitAll().anyRequest() - * .hasRole("USER").and() + * http.authorizeHttpRequests((authorize) -> authorize + * .requestMatchers("/public/**").permitAll() + * .anyRequest().hasRole("USER")) * // Possibly more configuration ... * .formLogin() // enable form based log in * // set permitAll for all URLs associated with Form Login diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java index a6af1e782e..d3f83c2b1a 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java @@ -21,6 +21,7 @@ import java.util.UUID; import org.springframework.security.authentication.AnonymousAuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.SecurityConfigurer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -57,7 +58,7 @@ public final class AnonymousConfigurer> /** * Creates a new instance - * @see HttpSecurity#anonymous() + * @see HttpSecurity#anonymous(Customizer) */ public AnonymousConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurer.java index b5e7f93e87..11e54195c9 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurer.java @@ -43,6 +43,8 @@ import org.springframework.security.web.access.channel.SecureChannelProcessor; import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.matcher.RequestMatcher; +import static org.springframework.security.config.Customizer.withDefaults; + /** * Adds channel security (i.e. requires HTTPS or HTTP) to an application. In order for * {@link ChannelSecurityConfigurer} to be useful, at least one {@link RequestMatcher} @@ -96,7 +98,7 @@ public final class ChannelSecurityConfigurer> /** * Creates a new instance - * @see HttpSecurity#requiresChannel() + * @see HttpSecurity#requiresChannel(Customizer) */ public ChannelSecurityConfigurer(ApplicationContext context) { this.REGISTRY = new ChannelRequestMatcherRegistry(context); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java index 58129ff1d6..c35c2eb5e2 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurer.java @@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.util.Assert; @@ -57,7 +58,7 @@ public class CorsConfigurer> extends AbstractHt /** * Creates a new instance * - * @see HttpSecurity#cors() + * @see HttpSecurity#cors(Customizer) */ public CorsConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java index 6188a7f056..c16f150d48 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java @@ -27,6 +27,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.context.ApplicationContext; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -56,6 +57,8 @@ import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import static org.springframework.security.config.Customizer.withDefaults; + /** * Adds * CSRF @@ -103,7 +106,7 @@ public final class CsrfConfigurer> /** * Creates a new instance - * @see HttpSecurity#csrf() + * @see HttpSecurity#csrf(Customizer) */ public CsrfConfigurer(ApplicationContext context) { this.context = context; @@ -163,9 +166,8 @@ public final class CsrfConfigurer> * *
 	 * http
-	 *     .csrf()
-	 *         .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With")))
-	 *         .and()
+	 *     .csrf((csrf) -> csrf
+	 *         .ignoringRequestMatchers((request) -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))))
 	 *     ...
 	 * 
* @@ -191,9 +193,8 @@ public final class CsrfConfigurer> * *
 	 * http
-	 *     .csrf()
-	 *         .ignoringRequestMatchers("/sockjs/**")
-	 *         .and()
+	 *     .csrf((csrf) -> csrf
+	 *         .ignoringRequestMatchers("/sockjs/**"))
 	 *     ...
 	 * 
* diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurer.java index 7640de9afb..57ecaedb87 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurer.java @@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers; import java.util.LinkedHashMap; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.AuthenticationEntryPoint; @@ -76,7 +77,7 @@ public final class ExceptionHandlingConfigurer> /** * Creates a new instance - * @see HttpSecurity#exceptionHandling() + * @see HttpSecurity#exceptionHandling(Customizer) */ public ExceptionHandlingConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java index c3a9bd1377..f622c4936e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java @@ -29,6 +29,7 @@ import org.springframework.security.access.SecurityConfig; import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.config.Customizer; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -41,6 +42,8 @@ import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import static org.springframework.security.config.Customizer.withDefaults; + /** * Adds URL based authorization based upon SpEL expressions to an application. At least * one {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped @@ -77,7 +80,7 @@ import org.springframework.util.StringUtils; * @author Yanming Zhou * @author Ngoc Nhan * @since 3.2 - * @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests() + * @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests(Customizer) * @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead */ @Deprecated @@ -104,7 +107,7 @@ public final class ExpressionUrlAuthorizationConfigurer> extends /** * Creates a new instance - * @see HttpSecurity#formLogin() + * @see HttpSecurity#formLogin(Customizer) */ public FormLoginConfigurer() { super(new UsernamePasswordAuthenticationFilter(), null); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java index 569dc8d124..e99cec8f54 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java @@ -48,6 +48,8 @@ import org.springframework.security.web.header.writers.frameoptions.XFrameOption import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; +import static org.springframework.security.config.Customizer.withDefaults; + /** *

* Adds the Security HTTP headers to the response. Security HTTP headers is activated by @@ -111,7 +113,7 @@ public class HeadersConfigurer> /** * Creates a new instance * - * @see HttpSecurity#headers() + * @see HttpSecurity#headers(Customizer) */ public HeadersConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java index 5180267226..39b53b9a20 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java @@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.AuthenticationEntryPoint; @@ -98,7 +99,7 @@ public final class HttpBasicConfigurer> /** * Creates a new instance - * @see HttpSecurity#httpBasic() + * @see HttpSecurity#httpBasic(Customizer) */ public HttpBasicConfigurer() { realmName(DEFAULT_REALM); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurer.java index 7c505924eb..be5359caa6 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurer.java @@ -22,6 +22,7 @@ import java.util.Set; import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever; @@ -77,7 +78,7 @@ public final class JeeConfigurer> extends Abstr /** * Creates a new instance - * @see HttpSecurity#jee() + * @see HttpSecurity#jee(Customizer) */ public JeeConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.java index 3c89ccbaf4..fa9a8298a2 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.java @@ -23,6 +23,7 @@ import java.util.List; import jakarta.servlet.http.HttpSession; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.SecurityConfigurer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.RequestMatcherFactory; @@ -92,7 +93,7 @@ public final class LogoutConfigurer> /** * Creates a new instance - * @see HttpSecurity#logout() + * @see HttpSecurity#logout(Customizer) */ public LogoutConfigurer() { } @@ -150,7 +151,7 @@ public final class LogoutConfigurer> * @param logoutUrl the URL that will invoke logout. * @return the {@link LogoutConfigurer} for further customization * @see #logoutRequestMatcher(RequestMatcher) - * @see HttpSecurity#csrf() + * @see HttpSecurity#csrf(Customizer) */ public LogoutConfigurer logoutUrl(String logoutUrl) { this.logoutRequestMatcher = null; diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java index 621d21a349..9a939f2b8c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java @@ -16,6 +16,7 @@ package org.springframework.security.config.annotation.web.configurers; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; @@ -70,7 +71,7 @@ public final class SecurityContextConfigurer> /** * Creates a new instance - * @see HttpSecurity#securityContext() + * @see HttpSecurity#securityContext(Customizer) */ public SecurityContextConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurer.java index a1b64f1ea0..758e290048 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurer.java @@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.ApplicationContext; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.core.GrantedAuthorityDefaults; @@ -66,7 +67,7 @@ public final class ServletApiConfigurer> /** * Creates a new instance - * @see HttpSecurity#servletApi() + * @see HttpSecurity#servletApi(Customizer) */ public ServletApiConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java index fa601b9449..0ac0480e03 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java @@ -66,6 +66,8 @@ import org.springframework.security.web.session.SimpleRedirectSessionInformation import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import static org.springframework.security.config.Customizer.withDefaults; + /** * Allows configuring session management. * @@ -152,7 +154,7 @@ public final class SessionManagementConfigurer> /** * Creates a new instance - * @see HttpSecurity#sessionManagement() + * @see HttpSecurity#sessionManagement(Customizer) */ public SessionManagementConfigurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java index d6241a0fbe..8760598f46 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/X509Configurer.java @@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.ApplicationContext; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.Authentication; @@ -90,7 +91,7 @@ public final class X509Configurer> /** * Creates a new instance * - * @see HttpSecurity#x509() + * @see HttpSecurity#x509(Customizer) */ public X509Configurer() { } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 355e49670b..d270f55731 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -104,6 +104,8 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; +import static org.springframework.security.config.Customizer.withDefaults; + /** * An {@link AbstractHttpConfigurer} for OAuth 2.0 Login, which leverages the OAuth 2.0 * Authorization Code Grant Flow. @@ -155,7 +157,7 @@ import org.springframework.util.ReflectionUtils; * @author Kazuki Shimizu * @author Ngoc Nhan * @since 5.0 - * @see HttpSecurity#oauth2Login() + * @see HttpSecurity#oauth2Login(Customizer) * @see OAuth2AuthorizationRequestRedirectFilter * @see OAuth2LoginAuthenticationFilter * @see ClientRegistrationRepository diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java index 1f7efc1829..e6d92ce33e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java @@ -27,6 +27,7 @@ import org.opensaml.core.Version; import org.springframework.context.ApplicationContext; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.RequestMatcherFactory; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -111,7 +112,7 @@ import org.springframework.util.StringUtils; * * * @since 5.2 - * @see HttpSecurity#saml2Login() + * @see HttpSecurity#saml2Login(Customizer) * @see Saml2WebSsoAuthenticationFilter * @see Saml2WebSsoAuthenticationRequestFilter * @see RelyingPartyRegistrationRepository diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java index fc9950d964..22358ea3a2 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java @@ -71,6 +71,8 @@ import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.ParameterRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import static org.springframework.security.config.Customizer.withDefaults; + /** * Adds SAML 2.0 logout support. * @@ -135,7 +137,7 @@ public final class Saml2LogoutConfigurer> /** * Creates a new instance - * @see HttpSecurity#logout() + * @see HttpSecurity#logout(Customizer) */ public Saml2LogoutConfigurer(ApplicationContext context) { this.context = context; @@ -158,7 +160,7 @@ public final class Saml2LogoutConfigurer> * @param logoutUrl the URL that will invoke logout * @return the {@link LogoutConfigurer} for further customizations * @see LogoutConfigurer#logoutUrl(String) - * @see HttpSecurity#csrf() + * @see HttpSecurity#csrf(Customizer) */ public Saml2LogoutConfigurer logoutUrl(String logoutUrl) { this.logoutUrl = logoutUrl; From 1a7b1fcc7c97e5ade390b158808f33642b321d0d Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:28:51 -0600 Subject: [PATCH 402/504] Remove HttpSecurity and() DSL Methods This commit removes all and() methods that have been deprecated in the HttpSecurity DSL with the exception of featurePolicy, which will be removed when that feature is removed. Note that since featurePolicy does not have a lambda equivalent, the and support needs to remain for the moment. Issue gh-13067 --- .../annotation/SecurityConfigurerAdapter.java | 11 - .../LdapAuthenticationProviderConfigurer.java | 4 + .../InMemoryUserDetailsManagerConfigurer.java | 4 + .../annotation/web/builders/HttpSecurity.java | 1551 ----------------- .../AuthorizeHttpRequestsConfigurer.java | 11 - .../ChannelSecurityConfigurer.java | 17 - .../web/configurers/CsrfConfigurer.java | 12 +- .../ExpressionUrlAuthorizationConfigurer.java | 4 +- .../web/configurers/HeadersConfigurer.java | 434 +---- .../SessionManagementConfigurer.java | 13 - .../UrlAuthorizationConfigurer.java | 2 +- .../oauth2/client/OAuth2ClientConfigurer.java | 23 - .../oauth2/client/OAuth2LoginConfigurer.java | 103 -- .../oauth2/client/OidcLogoutConfigurer.java | 5 - .../OAuth2ResourceServerConfigurer.java | 40 - .../saml2/Saml2LogoutConfigurer.java | 54 - 16 files changed, 16 insertions(+), 2272 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java b/config/src/main/java/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java index 8136bf7070..6db7ca8b73 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java +++ b/config/src/main/java/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java @@ -50,17 +50,6 @@ public abstract class SecurityConfigurerAdapter> public void configure(B builder) throws Exception { } - /** - * Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}. - * This is useful for method chaining. - * @return the {@link SecurityBuilder} for further customizations - * @deprecated For removal in 7.0. Use the lambda based configuration instead. - */ - @Deprecated(since = "6.1", forRemoval = true) - public B and() { - return getBuilder(); - } - /** * Gets the {@link SecurityBuilder}. Cannot be null. * @return the {@link SecurityBuilder} diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java index 0f47afa594..1a44dbcebe 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java @@ -386,6 +386,10 @@ public class LdapAuthenticationProviderConfigurer())); } + public B and() { + return getBuilder(); + } + } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index e441b92504..4a4c3cc42e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -103,8 +103,6 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; -import static org.springframework.security.config.Customizer.withDefaults; - /** * A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the * namespace configuration. It allows configuring web based security for specific http @@ -218,114 +216,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * @Configuration - * @EnableWebSecurity - * public class CsrfSecurityConfig { - * - * @Bean - * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - * http - * .headers() - * .contentTypeOptions() - * .and() - * .xssProtection() - * .and() - * .cacheControl() - * .and() - * .httpStrictTransportSecurity() - * .and() - * .frameOptions() - * .and() - * ...; - * return http.build(); - * } - * } - *

- * - * You can disable the headers using the following: - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class CsrfSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.headers().disable()
-	 * 			...;
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * - * You can enable only a few of the headers by first invoking - * {@link HeadersConfigurer#defaultsDisabled()} and then invoking the appropriate - * methods on the {@link #headers(withDefaults())} result. For example, the following - * will enable {@link HeadersConfigurer#cacheControl()} and - * {@link HeadersConfigurer#frameOptions()} only. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class CsrfSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.headers()
-	 * 				.defaultsDisabled()
-	 * 				.cacheControl()
-	 * 				.and()
-	 * 				.frameOptions()
-	 * 				.and()
-	 * 			...;
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * - * You can also choose to keep the defaults but explicitly disable a subset of - * headers. For example, the following will enable all the default headers except - * {@link HeadersConfigurer#frameOptions()}. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class CsrfSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.headers()
-	 * 				 .frameOptions()
-	 * 				 	.disable()
-	 * 				 .and()
-	 * 			...;
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * @return the {@link HeadersConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or - * {@code headers(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - * @see HeadersConfigurer - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer headers() throws Exception { - return getOrApply(new HeadersConfigurer<>()); - } - /** * Adds the Security headers to the response. This is activated by default when using * {@link EnableWebSecurity}. @@ -428,23 +318,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CorsConfigurer cors() throws Exception { - return getOrApply(new CorsConfigurer<>()); - } - /** * Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is * provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is @@ -475,69 +348,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration - * - * The following configuration demonstrates how to enforce that only a single instance - * of a user is authenticated at a time. If a user authenticates with the username - * "user" without logging out and an attempt to authenticate with "user" is made the - * first session will be forcibly terminated and sent to the "/login?expired" URL. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class SessionManagementSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().anyRequest().hasRole("USER").and().formLogin()
-	 * 				.permitAll().and().sessionManagement().maximumSessions(1)
-	 * 				.expiredUrl("/login?expired");
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * - * When using {@link SessionManagementConfigurer#maximumSessions(int)}, do not forget - * to configure {@link HttpSessionEventPublisher} for the application to ensure that - * expired sessions are cleaned up. - * - * In a web.xml this can be configured using the following: - * - *
-	 * <listener>
-	 *      <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
-	 * </listener>
-	 * 
- * - * Alternatively, - * {@link AbstractSecurityWebApplicationInitializer#enableHttpSessionEventPublisher()} - * could return true. - * @return the {@link SessionManagementConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #sessionManagement(Customizer)} or - * {@code sessionManagement(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public SessionManagementConfigurer sessionManagement() throws Exception { - return getOrApply(new SessionManagementConfigurer<>()); - } - /** * Allows configuring of Session Management. * @@ -636,61 +446,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * @return the {@link PortMapperConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #portMapper(Customizer)} or - * {@code portMapper(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - * @see #requiresChannel(withDefaults()) - */ - @Deprecated(since = "6.1", forRemoval = true) - public PortMapperConfigurer portMapper() throws Exception { - return getOrApply(new PortMapperConfigurer<>()); - } - - /** - * Allows configuring a {@link PortMapper} that is available from - * {@link HttpSecurity#getSharedObject(Class)}. Other provided - * {@link SecurityConfigurer} objects use this configured {@link PortMapper} as a - * default {@link PortMapper} when redirecting from HTTP to HTTPS or from HTTPS to - * HTTP (for example when used in combination with - * {@link #requiresChannel(withDefaults())}. By default Spring Security uses a - * {@link PortMapperImpl} which maps the HTTP port 8080 to the HTTPS port 8443 and the - * HTTP port of 80 to the HTTPS port of 443. - * - *

Example Configuration

- * - * The following configuration will ensure that redirects within Spring Security from - * HTTP of a port of 9090 will redirect to HTTPS port of 9443 and the HTTP port of 80 - * to the HTTPS port of 443. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class PortMapperSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 	 * 		http
 	 * 			.requiresChannel((requiresChannel) ->
 	 * 				requiresChannel
@@ -727,83 +482,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration
-	 *
-	 * The following configuration will use the principal found on the
-	 * {@link HttpServletRequest} and if the user is in the role "ROLE_USER" or
-	 * "ROLE_ADMIN" will add that to the resulting {@link Authentication}.
-	 *
-	 * 
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class JeeSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and()
-	 * 		// Example jee() configuration
-	 * 				.jee().mappableRoles("USER", "ADMIN");
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * - * Developers wishing to use pre authentication with the container will need to ensure - * their web.xml configures the security constraints. For example, the web.xml (there - * is no equivalent Java based configuration supported by the Servlet specification) - * might look like: - * - *
-	 * <login-config>
-	 *     <auth-method>FORM</auth-method>
-	 *     <form-login-config>
-	 *         <form-login-page>/login</form-login-page>
-	 *         <form-error-page>/login?error</form-error-page>
-	 *     </form-login-config>
-	 * </login-config>
-	 *
-	 * <security-role>
-	 *     <role-name>ROLE_USER</role-name>
-	 * </security-role>
-	 * <security-constraint>
-	 *     <web-resource-collection>
-	 *     <web-resource-name>Public</web-resource-name>
-	 *         <description>Matches unconstrained pages</description>
-	 *         <url-pattern>/login</url-pattern>
-	 *         <url-pattern>/logout</url-pattern>
-	 *         <url-pattern>/resources/*</url-pattern>
-	 *     </web-resource-collection>
-	 * </security-constraint>
-	 * <security-constraint>
-	 *     <web-resource-collection>
-	 *         <web-resource-name>Secured Areas</web-resource-name>
-	 *         <url-pattern>/*</url-pattern>
-	 *     </web-resource-collection>
-	 *     <auth-constraint>
-	 *         <role-name>ROLE_USER</role-name>
-	 *     </auth-constraint>
-	 * </security-constraint>
-	 * 
- * - * Last you will need to configure your container to contain the user with the correct - * roles. This configuration is specific to the Servlet Container, so consult your - * Servlet Container's documentation. - * @return the {@link JeeConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #jee(Customizer)} or - * {@code jee(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public JeeConfigurer jee() throws Exception { - return getOrApply(new JeeConfigurer<>()); - } - /** * Configures container based pre authentication. In this case, authentication is * managed by the Servlet Container. @@ -885,41 +563,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration - * - * The following configuration will attempt to extract the username from the X509 - * certificate. Remember that the Servlet Container will need to be configured to - * request client certificates in order for this to work. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class X509SecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and()
-	 * 		// Example x509() configuration
-	 * 				.x509();
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * @return the {@link X509Configurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or - * {@code x509(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public X509Configurer x509() throws Exception { - return getOrApply(new X509Configurer<>()); - } - /** * Configures X509 based pre authentication. * @@ -956,54 +599,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration - * - * The following configuration demonstrates how to allow token based remember me - * authentication. Upon authenticating if the HTTP parameter named "remember-me" - * exists, then the user will be remembered even after their - * {@link jakarta.servlet.http.HttpSession} expires. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class RememberMeSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().formLogin()
-	 * 				.permitAll().and()
-	 * 				// Example Remember Me Configuration
-	 * 				.rememberMe();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link RememberMeConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #rememberMe(Customizer)} or - * {@code rememberMe(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public RememberMeConfigurer rememberMe() throws Exception { - return getOrApply(new RememberMeConfigurer<>()); - } - /** * Allows configuring of Remember Me authentication. * @@ -1053,106 +648,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configurations - * - * The most basic example is to configure all URLs to require the role "ROLE_USER". - * The configuration below requires authentication to every URL and will grant access - * to both the user "admin" and "user". - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().formLogin();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * We can also configure multiple URLs. The configuration below requires - * authentication to every URL and will grant access to URLs starting with /admin/ to - * only the "admin" user. All other URLs either user can access. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/admin/**").hasRole("ADMIN")
-	 * 				.requestMatchers("/**").hasRole("USER").and().formLogin();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * Note that the matchers are considered in order. Therefore, the following is invalid - * because the first matcher matches every request and will never get to the second - * mapping: - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").requestMatchers("/admin/**")
-	 * 			.hasRole("ADMIN")
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests() - throws Exception { - ApplicationContext context = getContext(); - return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry(); - } - /** * Allows restricting access based upon the {@link HttpServletRequest} using * {@link RequestMatcher} implementations (i.e. via URL patterns). @@ -1272,119 +767,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configurations - * - * The most basic example is to configure all URLs to require the role "ROLE_USER". - * The configuration below requires authentication to every URL and will grant access - * to both the user "admin" and "user". - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeHttpRequests()
-	 * 				.requestMatchers("/**").hasRole("USER")
-	 * 				.and()
-	 * 			.formLogin();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * We can also configure multiple URLs. The configuration below requires - * authentication to every URL and will grant access to URLs starting with /admin/ to - * only the "admin" user. All other URLs either user can access. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeHttpRequests()
-	 * 				.requestMatchers("/admin").hasRole("ADMIN")
-	 * 				.requestMatchers("/**").hasRole("USER")
-	 * 				.and()
-	 * 			.formLogin();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * Note that the matchers are considered in order. Therefore, the following is invalid - * because the first matcher matches every request and will never get to the second - * mapping: - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeHttpRequests()
-	 * 				.requestMatchers("/**").hasRole("USER")
-	 * 				.requestMatchers("/admin/**").hasRole("ADMIN")
-	 * 				.and()
-	 * 			.formLogin();
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * @return the {@link HttpSecurity} for further customizations - * @throws Exception - * @since 5.6 - * @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequests() - throws Exception { - ApplicationContext context = getContext(); - return getOrApply(new AuthorizeHttpRequestsConfigurer<>(context)).getRegistry(); - } - /** * Allows restricting access based upon the {@link HttpServletRequest} using * {@link RequestMatcher} implementations (i.e. via URL patterns). @@ -1502,25 +884,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public RequestCacheConfigurer requestCache() throws Exception { - return getOrApply(new RequestCacheConfigurer<>()); - } - /** * Allows configuring the Request Cache. For example, a protected page (/protected) * may be requested prior to authentication. The application will redirect the user to @@ -1562,22 +925,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ExceptionHandlingConfigurer exceptionHandling() throws Exception { - return getOrApply(new ExceptionHandlingConfigurer<>()); - } - /** * Allows configuring exception handling. This is automatically applied when using * {@link EnableWebSecurity}. @@ -1619,23 +966,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public SecurityContextConfigurer securityContext() throws Exception { - return getOrApply(new SecurityContextConfigurer<>()); - } - /** * Sets up management of the {@link SecurityContext} on the * {@link SecurityContextHolder} between {@link HttpServletRequest}'s. This is @@ -1670,23 +1000,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServletApiConfigurer servletApi() throws Exception { - return getOrApply(new ServletApiConfigurer<>()); - } - /** * Integrates the {@link HttpServletRequest} methods with the values found on the * {@link SecurityContext}. This is automatically applied when using @@ -1718,37 +1031,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * @Configuration - * @EnableWebSecurity - * public class CsrfSecurityConfig { - * - * @Bean - * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - * http - * .csrf().disable() - * ...; - * return http.build(); - * } - * } - *
- * @return the {@link CsrfConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or - * {@code csrf(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CsrfConfigurer csrf() throws Exception { - ApplicationContext context = getContext(); - return getOrApply(new CsrfConfigurer<>(context)); - } - /** * Enables CSRF protection. This is activated by default when using * {@link EnableWebSecurity}. You can disable it using: @@ -1797,57 +1079,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * @return the {@link LogoutConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or - * {@code logout(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public LogoutConfigurer logout() throws Exception { - return getOrApply(new LogoutConfigurer<>()); - } - - /** - * Provides logout support. This is automatically applied when using - * {@link EnableWebSecurity}. The default is that accessing the URL "/logout" will log - * the user out by invalidating the HTTP Session, cleaning up any - * {@link #rememberMe(withDefaults())} authentication that was configured, clearing - * the {@link SecurityContextHolder}, and then redirect to "/login?success". - * - *

Example Custom Configuration

- * - * The following customization to log out when the URL "/custom-logout" is invoked. - * Log out will remove the cookie named "remove", not invalidate the HttpSession, - * clear the SecurityContextHolder, and upon completion redirect to "/logout-success". - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class LogoutSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 	 * 		http
 	 * 			.authorizeRequests((authorizeRequests) ->
 	 * 				authorizeRequests
@@ -1885,94 +1116,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration
-	 *
-	 * The following configuration demonstrates how to specify that anonymous users should
-	 * contain the role "ROLE_ANON" instead.
-	 *
-	 * 
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AnonymousSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests()
-	 * 				.requestMatchers("/**").hasRole("USER")
-	 * 				.and()
-	 * 			.formLogin()
-	 * 				.and()
-	 * 			// sample anonymous customization
-	 * 			.anonymous().authorities("ROLE_ANON");
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * - * The following demonstrates how to represent anonymous users as null. Note that this - * can cause {@link NullPointerException} in code that assumes anonymous - * authentication is enabled. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AnonymousSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests()
-	 * 				.requestMatchers("/**").hasRole("USER")
-	 * 				.and()
-	 * 			.formLogin()
-	 * 				.and()
-	 * 			// sample anonymous customization
-	 * 			.anonymous().disable();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link AnonymousConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or - * {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public AnonymousConfigurer anonymous() throws Exception { - return getOrApply(new AnonymousConfigurer<>()); - } - /** * Allows configuring how an anonymous user is represented. This is automatically * applied when used in conjunction with {@link EnableWebSecurity}. By default @@ -2063,86 +1206,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configurations - * - * The most basic configuration defaults to automatically generating a login page at - * the URL "/login", redirecting to "/login?error" for authentication failure. The - * details of the login page can be found on - * {@link FormLoginConfigurer#loginPage(String)} - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class FormLoginSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().formLogin();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * - * The configuration below demonstrates customizing the defaults. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class FormLoginSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().formLogin()
-	 * 				.usernameParameter("username") // default is username
-	 * 				.passwordParameter("password") // default is password
-	 * 				.loginPage("/authentication/login") // default is /login with an HTTP get
-	 * 				.failureUrl("/authentication/login?failed") // default is /login?error
-	 * 				.loginProcessingUrl("/authentication/login/process"); // default is /login
-	 * 																		// with an HTTP
-	 * 																		// post
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link FormLoginConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or - * {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - * @see FormLoginConfigurer#loginPage(String) - */ - @Deprecated(since = "6.1", forRemoval = true) - public FormLoginConfigurer formLogin() throws Exception { - return getOrApply(new FormLoginConfigurer<>()); - } - /** * Specifies to support form based authentication. If * {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page @@ -2230,100 +1293,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - *
- * - * The "authentication flow" is implemented using the Web Browser SSO - * Profile, using POST and REDIRECT bindings, as documented in the - * SAML V2.0 - * Core,Profiles and Bindings specifications.
- *
- * - * As a prerequisite to using this feature, is that you have a SAML v2.0 Identity - * Provider to provide an assertion. The representation of the Service Provider, the - * relying party, and the remote Identity Provider, the asserting party is contained - * within {@link RelyingPartyRegistration}.
- *
- * - * {@link RelyingPartyRegistration}(s) are composed within a - * {@link RelyingPartyRegistrationRepository}, which is required and must be - * registered with the {@link ApplicationContext} or configured via - * saml2Login().relyingPartyRegistrationRepository(..).
- *
- * - * The default configuration provides an auto-generated login page at - * "/login" and redirects to - * "/login?error" when an authentication error occurs. The - * login page will display each of the identity providers with a link that is capable - * of initiating the "authentication flow".
- *
- * - *

- *

Example Configuration

- * - * The following example shows the minimal configuration required, using SimpleSamlPhp - * as the Authentication Provider. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class Saml2LoginSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests()
-	 * 				.anyRequest().authenticated()
-	 * 				.and()
-	 * 			.saml2Login();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 *	@Bean
-	 *	public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
-	 *		return new InMemoryRelyingPartyRegistrationRepository(this.getSaml2RelyingPartyRegistration());
-	 *	}
-	 *
-	 * 	private RelyingPartyRegistration getSaml2RelyingPartyRegistration() {
-	 * 		//remote IDP entity ID
-	 * 		String idpEntityId = "https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php";
-	 * 		//remote WebSSO Endpoint - Where to Send AuthNRequests to
-	 * 		String webSsoEndpoint = "https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php";
-	 * 		//local registration ID
-	 * 		String registrationId = "simplesamlphp";
-	 * 		//local entity ID - autogenerated based on URL
-	 * 		String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
-	 * 		//local signing (and decryption key)
-	 * 		Saml2X509Credential signingCredential = getSigningCredential();
-	 * 		//IDP certificate for verification of incoming messages
-	 * 		Saml2X509Credential idpVerificationCertificate = getVerificationCertificate();
-	 * 		return RelyingPartyRegistration.withRegistrationId(registrationId)
-	 * 				.remoteIdpEntityId(idpEntityId)
-	 * 				.idpWebSsoUrl(webSsoEndpoint)
-	 * 				.credential(signingCredential)
-	 * 				.credential(idpVerificationCertificate)
-	 * 				.localEntityIdTemplate(localEntityIdTemplate)
-	 * 				.build();
-	 * 	}
-	 * }
-	 * 
- * - *

- * @return the {@link Saml2LoginConfigurer} for further customizations - * @throws Exception - * @since 5.2 - * @deprecated For removal in 7.0. Use {@link #saml2Login(Customizer)} or - * {@code saml2Login(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public Saml2LoginConfigurer saml2Login() throws Exception { - return getOrApply(new Saml2LoginConfigurer<>()); - } - /** * Configures authentication support using an SAML 2.0 Service Provider.
*
@@ -2486,80 +1455,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - *
- * - * Implements the Single Logout Profile, using POST and REDIRECT bindings, as - * documented in the - * SAML V2.0 - * Core, Profiles and Bindings specifications.
- *
- * - * As a prerequisite to using this feature, is that you have a SAML v2.0 Asserting - * Party to sent a logout request to. The representation of the relying party and the - * asserting party is contained within {@link RelyingPartyRegistration}.
- *
- * - * {@link RelyingPartyRegistration}(s) are composed within a - * {@link RelyingPartyRegistrationRepository}, which is required and must be - * registered with the {@link ApplicationContext} or configured via - * {@link #saml2Login(withDefaults())}.
- *
- * - * The default configuration provides an auto-generated logout endpoint at - * "/logout" and redirects to /login?logout when - * logout completes.
- *
- * - *

- *

Example Configuration

- * - * The following example shows the minimal configuration required, using a - * hypothetical asserting party. - * - *
-	 *	@EnableWebSecurity
-	 *	@Configuration
-	 *	public class Saml2LogoutSecurityConfig {
-	 *		@Bean
-	 *		public SecurityFilterChain web(HttpSecurity http) throws Exception {
-	 *			http
-	 *				.authorizeRequests()
-	 *					.anyRequest().authenticated()
-	 *					.and()
-	 *				.saml2Login()
-	 *					.and()
-	 *				.saml2Logout();
-	 *			return http.build();
-	 *		}
-	 *
-	 *		@Bean
-	 *		public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
-	 *			RelyingPartyRegistration registration = RelyingPartyRegistrations
-	 *					.withMetadataLocation("https://ap.example.org/metadata")
-	 *					.registrationId("simple")
-	 *					.build();
-	 *			return new InMemoryRelyingPartyRegistrationRepository(registration);
-	 *		}
-	 *	}
-	 * 
- * - *

- * @return the {@link Saml2LoginConfigurer} for further customizations - * @throws Exception - * @since 5.6 - * @deprecated For removal in 7.0. Use {@link #saml2Logout(Customizer)} or - * {@code saml2Logout(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public Saml2LogoutConfigurer saml2Logout() throws Exception { - return getOrApply(new Saml2LogoutConfigurer<>(getContext())); - } - /** * Configures a SAML 2.0 metadata endpoint that presents relying party configurations * in an {@code } payload. @@ -2610,163 +1505,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder} payload. - * - *

- * By default, the endpoints are {@code /saml2/metadata} and - * {@code /saml2/metadata/{registrationId}} though note that also - * {@code /saml2/service-provider-metadata/{registrationId}} is recognized for - * backward compatibility purposes. - * - *

- *

Example Configuration

- * - * The following example shows the minimal configuration required, using a - * hypothetical asserting party. - * - *
-	 *	@EnableWebSecurity
-	 *	@Configuration
-	 *	public class Saml2LogoutSecurityConfig {
-	 *		@Bean
-	 *		public SecurityFilterChain web(HttpSecurity http) throws Exception {
-	 *			http
-	 *				.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
-	 *				.saml2Metadata(Customizer.withDefaults());
-	 *			return http.build();
-	 *		}
-	 *
-	 *		@Bean
-	 *		public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
-	 *			RelyingPartyRegistration registration = RelyingPartyRegistrations
-	 *					.withMetadataLocation("https://ap.example.org/metadata")
-	 *					.registrationId("simple")
-	 *					.build();
-	 *			return new InMemoryRelyingPartyRegistrationRepository(registration);
-	 *		}
-	 *	}
-	 * 
- * @return the {@link Saml2MetadataConfigurer} for further customizations - * @throws Exception - * @since 6.1 - * @deprecated For removal in 7.0. Use {@link #saml2Metadata(Customizer)} or - * {@code saml2Metadata(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public Saml2MetadataConfigurer saml2Metadata() throws Exception { - return getOrApply(new Saml2MetadataConfigurer<>(getContext())); - } - - /** - * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 - * Provider.
- *
- * - * The "authentication flow" is implemented using the Authorization Code - * Grant, as specified in the - * OAuth 2.0 - * Authorization Framework and OpenID Connect - * Core 1.0 specification.
- *
- * - * As a prerequisite to using this feature, you must register a client with a - * provider. The client registration information may than be used for configuring a - * {@link org.springframework.security.oauth2.client.registration.ClientRegistration} - * using a - * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder}. - *
- *
- * - * {@link org.springframework.security.oauth2.client.registration.ClientRegistration}(s) - * are composed within a - * {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository}, - * which is required and must be registered with the {@link ApplicationContext} - * or configured via oauth2Login().clientRegistrationRepository(..).
- *
- * - * The default configuration provides an auto-generated login page at - * "/login" and redirects to - * "/login?error" when an authentication error occurs. The - * login page will display each of the clients with a link that is capable of - * initiating the "authentication flow".
- *
- * - *

- *

Example Configuration

- * - * The following example shows the minimal configuration required, using Google as the - * Authentication Provider. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class OAuth2LoginSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests()
-	 * 				.anyRequest().authenticated()
-	 * 				.and()
-	 * 			.oauth2Login();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 *	@Bean
-	 *	public ClientRegistrationRepository clientRegistrationRepository() {
-	 *		return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
-	 *	}
-	 *
-	 * 	private ClientRegistration googleClientRegistration() {
-	 * 		return ClientRegistration.withRegistrationId("google")
-	 * 			.clientId("google-client-id")
-	 * 			.clientSecret("google-client-secret")
-	 * 			.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
-	 * 			.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
-	 * 			.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
-	 * 			.scope("openid", "profile", "email", "address", "phone")
-	 * 			.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
-	 * 			.tokenUri("https://www.googleapis.com/oauth2/v4/token")
-	 * 			.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
-	 * 			.userNameAttributeName(IdTokenClaimNames.SUB)
-	 * 			.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
-	 * 			.clientName("Google")
-	 * 			.build();
-	 *	}
-	 * }
-	 * 
- * - *

- * For more advanced configuration, see {@link OAuth2LoginConfigurer} for available - * options to customize the defaults. - * @return the {@link OAuth2LoginConfigurer} for further customizations - * @throws Exception - * @since 5.0 - * @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or - * {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - * @see Section 4.1 Authorization Code - * Grant - * @see Section 3.1 - * Authorization Code Flow - * @see org.springframework.security.oauth2.client.registration.ClientRegistration - * @see org.springframework.security.oauth2.client.registration.ClientRegistrationRepository - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginConfigurer oauth2Login() throws Exception { - return getOrApply(new OAuth2LoginConfigurer<>()); - } - /** * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 * Provider.
@@ -2880,27 +1618,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderdocumentation - * for more details. - * @see OAuth 2.0 Authorization - * Framework - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ClientConfigurer oauth2Client() throws Exception { - OAuth2ClientConfigurer configurer = getOrApply(new OAuth2ClientConfigurer<>()); - this.postProcess(configurer); - return configurer; - } - /** * Configures OAuth 2.0 Client support. * @@ -2940,25 +1657,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderOAuth 2.0 Authorization - * Framework - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ResourceServerConfigurer oauth2ResourceServer() throws Exception { - OAuth2ResourceServerConfigurer configurer = getOrApply( - new OAuth2ResourceServerConfigurer<>(getContext())); - this.postProcess(configurer); - return configurer; - } - /** * Configures OAuth 2.0 Resource Server support. * @@ -3051,55 +1749,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration - * - * The example below demonstrates how to require HTTPs for every request. Only - * requiring HTTPS for some requests is supported, but not recommended since an - * application that allows for HTTP introduces many security vulnerabilities. For one - * such example, read about - * Firesheep. - * - *

-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class ChannelSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().formLogin()
-	 * 				.and().requiresChannel().anyRequest().requiresSecure();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link ChannelSecurityConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #requiresChannel(Customizer)} or - * {@code requiresChannel(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ChannelSecurityConfigurer.ChannelRequestMatcherRegistry requiresChannel() throws Exception { - ApplicationContext context = getContext(); - return getOrApply(new ChannelSecurityConfigurer<>(context)).getRegistry(); - } - /** * Configures channel security. In order for this configuration to be useful at least * one mapping to a required channel must be provided. @@ -3205,50 +1854,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configuration - * - * The example below demonstrates how to configure HTTP Basic authentication for an - * application. The default realm is "Realm", but can be customized using - * {@link HttpBasicConfigurer#realmName(String)}. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class HttpBasicSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http.authorizeRequests().requestMatchers("/**").hasRole("USER").and().httpBasic();
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link HttpBasicConfigurer} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or - * {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HttpBasicConfigurer httpBasic() throws Exception { - return getOrApply(new HttpBasicConfigurer<>()); - } - /** * Configures HTTP Basic authentication. * @@ -3454,133 +2059,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * Invoking {@link #securityMatchers()} will not override previous invocations of - * {@link #securityMatchers()}}, {@link #securityMatchers(Customizer)} - * {@link #securityMatcher(String...)} and {@link #securityMatcher(RequestMatcher)} - *

- * - *

Example Configurations

- * - * The following configuration enables the {@link HttpSecurity} for URLs that begin - * with "/api/" or "/oauth/". - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class RequestMatchersSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.securityMatchers((matchers) -> matchers
-	 * 				.requestMatchers("/api/**", "/oauth/**")
-	 * 			)
-	 * 			.authorizeHttpRequests((authorize) -> authorize
-	 * 				anyRequest().hasRole("USER")
-	 * 			)
-	 * 			.httpBasic(withDefaults());
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * - * The configuration below is the same as the previous configuration. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class RequestMatchersSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.securityMatchers((matchers) -> matchers
-	 * 				.requestMatchers("/api/**")
-	 * 				.requestMatchers("/oauth/**")
-	 * 			)
-	 * 			.authorizeHttpRequests((authorize) -> authorize
-	 * 				anyRequest().hasRole("USER")
-	 * 			)
-	 * 			.httpBasic(withDefaults());
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * - * The configuration below is also the same as the above configuration. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class RequestMatchersSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.securityMatchers((matchers) -> matchers
-	 * 				.requestMatchers("/api/**")
-	 * 			)
-	 *			.securityMatchers((matchers) -> matchers
-	 *				.requestMatchers("/oauth/**")
-	 * 			)
-	 * 			.authorizeHttpRequests((authorize) -> authorize
-	 * 				anyRequest().hasRole("USER")
-	 * 			)
-	 * 			.httpBasic(withDefaults());
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user);
-	 * 	}
-	 * }
-	 * 
- * @return the {@link RequestMatcherConfigurer} for further customizations - * @deprecated For removal in 7.0. Use {@link #securityMatchers(Customizer)} or - * {@code securityMatchers(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public RequestMatcherConfigurer securityMatchers() { - return this.requestMatcherConfigurer; - } - /** * Allows specifying which {@link HttpServletRequest} instances this * {@link HttpSecurity} will be invoked on. This method allows for easily invoking the @@ -3855,35 +2333,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder - * @Configuration - * @EnableWebSecurity - * public class SecurityConfig { - * - * @Bean - * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - * http - * .securityMatchers((matchers) -> matchers - * .requestMatchers("/api/**") - * ) - * .authorizeHttpRequests((authorize) -> authorize - * .anyRequest().hasRole("USER") - * ) - * .httpBasic(Customizer.withDefaults()); - * return http.build(); - * } - * - * } - *
- */ - @Deprecated(since = "6.1", forRemoval = true) - public HttpSecurity and() { - return HttpSecurity.this; - } - } /** diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java index 725ee45802..879451012a 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java @@ -231,17 +231,6 @@ public final class AuthorizeHttpRequestsConfigurer> return this; } - /** - * Return the {@link SecurityBuilder} when done using the - * {@link SecurityConfigurer}. This is useful for method chaining. - * @return the type of {@link HttpSecurityBuilder} that is being configured - * @deprecated For removal in 7.0. Use - * {@link HttpSecurity#requiresChannel(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public H and() { - return ChannelSecurityConfigurer.this.and(); - } - } /** diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java index c16f150d48..1fe1faf6cd 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java @@ -57,8 +57,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import static org.springframework.security.config.Customizer.withDefaults; - /** * Adds * CSRF @@ -174,7 +172,8 @@ public final class CsrfConfigurer> * @since 5.1 */ public CsrfConfigurer ignoringRequestMatchers(RequestMatcher... requestMatchers) { - return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and(); + new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers); + return this; } /** @@ -202,7 +201,8 @@ public final class CsrfConfigurer> * @see AbstractRequestMatcherRegistry#requestMatchers(String...) */ public CsrfConfigurer ignoringRequestMatchers(String... patterns) { - return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns).and(); + new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(patterns); + return this; } /** @@ -386,10 +386,6 @@ public final class CsrfConfigurer> setApplicationContext(context); } - CsrfConfigurer and() { - return CsrfConfigurer.this; - } - @Override protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List requestMatchers) { CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(requestMatchers); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java index f622c4936e..bddafb1d2e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java @@ -42,8 +42,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import static org.springframework.security.config.Customizer.withDefaults; - /** * Adds URL based authorization based upon SpEL expressions to an application. At least * one {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped @@ -253,7 +251,7 @@ public final class ExpressionUrlAuthorizationConfigurer * Adds the Security HTTP headers to the response. Security HTTP headers is activated by @@ -129,26 +127,6 @@ public class HeadersConfigurer> return this; } - /** - * Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the - * X-Content-Type-Options: - * - *
-	 * X-Content-Type-Options: nosniff
-	 * 
- * @return the {@link ContentTypeOptionsConfig} for additional customizations - * @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} or - * {@code contentTypeOptions(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ContentTypeOptionsConfig contentTypeOptions() { - return this.contentTypeOptions.enable(); - } - /** * Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the * > return HeadersConfigurer.this; } - /** - * Note this is not comprehensive XSS protection! - * - *

- * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header - *

- * @return the {@link XXssConfig} for additional customizations - * @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or - * {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public XXssConfig xssProtection() { - return this.xssProtection.enable(); - } - /** * Note this is not comprehensive XSS protection! * @@ -203,26 +161,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the - * following headers: - *
    - *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • - *
  • Pragma: no-cache
  • - *
  • Expires: 0
  • - *
- * @return the {@link CacheControlConfig} for additional customizations - * @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or - * {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CacheControlConfig cacheControl() { - return this.cacheControl.enable(); - } - /** * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the * following headers: @@ -240,19 +178,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows customizing the {@link HstsHeaderWriter} which provides support for - * HTTP Strict Transport Security - * (HSTS). - * @return the {@link HstsConfig} for additional customizations - * @deprecated For removal in 7.0. Use - * {@link #httpStrictTransportSecurity(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HstsConfig httpStrictTransportSecurity() { - return this.hsts.enable(); - } - /** * Allows customizing the {@link HstsHeaderWriter} which provides support for * HTTP Strict Transport Security @@ -266,20 +191,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows customizing the {@link XFrameOptionsHeaderWriter}. - * @return the {@link FrameOptionsConfig} for additional customizations - * @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or - * {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public FrameOptionsConfig frameOptions() { - return this.frameOptions.enable(); - } - /** * Allows customizing the {@link XFrameOptionsHeaderWriter}. * @param frameOptionsCustomizer the {@link Customizer} to provide more options for @@ -291,21 +202,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows customizing the {@link HpkpHeaderWriter} which provides support for - * HTTP Public Key Pinning (HPKP). - * @return the {@link HpkpConfig} for additional customizations - * - * @since 4.1 - * @deprecated see Certificate - * and Public Key Pinning for more context - */ - @Deprecated - public HpkpConfig httpPublicKeyPinning() { - return this.hpkp.enable(); - } - /** * Allows customizing the {@link HpkpHeaderWriter} which provides support for * HTTP Public Key Pinning (HPKP). @@ -322,39 +218,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - *

- * Allows configuration for Content Security - * Policy (CSP) Level 2. - *

- * - *

- * Calling this method automatically enables (includes) the Content-Security-Policy - * header in the response using the supplied security policy directive(s). - *

- * - *

- * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which - * supports the writing of the two headers as detailed in the W3C Candidate - * Recommendation: - *

- *
    - *
  • Content-Security-Policy
  • - *
  • Content-Security-Policy-Report-Only
  • - *
- * @return the {@link ContentSecurityPolicyConfig} for additional configuration - * @throws IllegalArgumentException if policyDirectives is null or empty - * @since 4.1 - * @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)} - * instead - * @see ContentSecurityPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) { - this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives); - return this.contentSecurityPolicy; - } - /** *

* Allows configuration for Content Security @@ -456,71 +319,6 @@ public class HeadersConfigurer> } } - /** - *

- * Allows configuration for Referrer - * Policy. - *

- * - *

- * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support - * the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Referrer-Policy
  • - *
- * - *

- * Default value is: - *

- * - *
-	 * Referrer-Policy: no-referrer
-	 * 
- * @return the {@link ReferrerPolicyConfig} for additional configuration - * @since 4.2 - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or - * {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - * @see ReferrerPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public ReferrerPolicyConfig referrerPolicy() { - this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); - return this.referrerPolicy; - } - - /** - *

- * Allows configuration for Referrer - * Policy. - *

- * - *

- * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support - * the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Referrer-Policy
  • - *
- * @return the {@link ReferrerPolicyConfig} for additional configuration - * @throws IllegalArgumentException if policy is null or empty - * @since 4.2 - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or - * {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - * @see ReferrerPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) { - this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy); - return this.referrerPolicy; - } - /** *

* Allows configuration for Referrer @@ -570,35 +368,6 @@ public class HeadersConfigurer> return this.featurePolicy; } - /** - *

- * Allows configuration for - * Permissions - * Policy. - *

- * - *

- * Configuration is provided to the {@link PermissionsPolicyHeaderWriter} which - * support the writing of the header as detailed in the W3C Technical Report: - *

- *
    - *
  • Permissions-Policy
  • - *
- * @return the {@link PermissionsPolicyConfig} for additional configuration - * @since 5.5 - * @deprecated For removal in 7.0. Use {@link #permissionsPolicyHeader(Customizer)} or - * {@code permissionsPolicy(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - * @see PermissionsPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public PermissionsPolicyConfig permissionsPolicy() { - this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter(); - return this.permissionsPolicy; - } - /** * Allows configuration for * Permissions @@ -645,26 +414,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows configuration for - * Cross-Origin-Opener-Policy header. - *

- * Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which - * responsible for writing the header. - *

- * @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration - * @since 5.7 - * @deprecated For removal in 7.0. Use {@link #crossOriginOpenerPolicy(Customizer)} - * instead - * @see CrossOriginOpenerPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() { - this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter(); - return this.crossOriginOpenerPolicy; - } - /** * Allows configuration for @@ -689,26 +438,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows configuration for - * Cross-Origin-Embedder-Policy header. - *

- * Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter} - * which is responsible for writing the header. - *

- * @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations - * @since 5.7 - * @deprecated For removal in 7.0. Use {@link #crossOriginEmbedderPolicy(Customizer)} - * instead - * @see CrossOriginEmbedderPolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() { - this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter(); - return this.crossOriginEmbedderPolicy; - } - /** * Allows configuration for @@ -733,26 +462,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows configuration for - * Cross-Origin-Resource-Policy header. - *

- * Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter} - * which is responsible for writing the header: - *

- * @return the {@link HeadersConfigurer} for additional customizations - * @since 5.7 - * @deprecated For removal in 7.0. Use {@link #crossOriginResourcePolicy(Customizer)} - * instead - * @see CrossOriginResourcePolicyHeaderWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() { - this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter(); - return this.crossOriginResourcePolicy; - } - /** * Allows configuration for @@ -791,17 +500,6 @@ public class HeadersConfigurer> */ public HeadersConfigurer disable() { this.writer = null; - return and(); - } - - /** - * Allows customizing the {@link HeadersConfigurer} - * @return the {@link HeadersConfigurer} for additional customization - * @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { return HeadersConfigurer.this; } @@ -866,21 +564,6 @@ public class HeadersConfigurer> */ public HeadersConfigurer disable() { this.writer = null; - return and(); - } - - /** - * Allows completing configuration of X-XSS-Protection and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or - * {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { return HeadersConfigurer.this; } @@ -914,21 +597,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows completing configuration of Cache Control and continuing configuration - * of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use {@link #cacheControl(Customizer)} or - * {@code cacheControl(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - /** * Ensures the Cache Control headers are enabled if they are not already. * @return the {@link CacheControlConfig} for additional customization @@ -1026,18 +694,6 @@ public class HeadersConfigurer> return HeadersConfigurer.this; } - /** - * Allows completing configuration of Strict Transport Security and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use - * {@link #httpStrictTransportSecurity(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - /** * Ensures that Strict-Transport-Security is enabled if it is not already * @return the {@link HstsConfig} for additional customization @@ -1065,7 +721,7 @@ public class HeadersConfigurer> */ public HeadersConfigurer deny() { this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY); - return and(); + return HeadersConfigurer.this; } /** @@ -1079,7 +735,7 @@ public class HeadersConfigurer> */ public HeadersConfigurer sameOrigin() { this.writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN); - return and(); + return HeadersConfigurer.this; } /** @@ -1088,20 +744,6 @@ public class HeadersConfigurer> */ public HeadersConfigurer disable() { this.writer = null; - return and(); - } - - /** - * Allows continuing customizing the headers configuration. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or - * {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { return HeadersConfigurer.this; } @@ -1319,18 +961,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows completing configuration of Content Security Policy and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } public final class ReferrerPolicyConfig { @@ -1351,18 +981,6 @@ public class HeadersConfigurer> return this; } - /** - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} or - * {@code referrerPolicy(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } public final class FeaturePolicyConfig { @@ -1401,18 +1019,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows completing configuration of Permissions Policy and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } public final class CrossOriginOpenerPolicyConfig { @@ -1434,18 +1040,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows completing configuration of Cross Origin Opener Policy and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use - * {@link #crossOriginOpenerPolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } public final class CrossOriginEmbedderPolicyConfig { @@ -1468,18 +1062,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows completing configuration of Cross-Origin-Embedder-Policy and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use - * {@link #crossOriginEmbedderPolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } public final class CrossOriginResourcePolicyConfig { @@ -1502,18 +1084,6 @@ public class HeadersConfigurer> return this; } - /** - * Allows completing configuration of Cross-Origin-Resource-Policy and continuing - * configuration of headers. - * @return the {@link HeadersConfigurer} for additional configuration - * @deprecated For removal in 7.0. Use - * {@link #crossOriginResourcePolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeadersConfigurer and() { - return HeadersConfigurer.this; - } - } } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java index 0ac0480e03..82c760a79d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java @@ -66,8 +66,6 @@ import org.springframework.security.web.session.SimpleRedirectSessionInformation import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import static org.springframework.security.config.Customizer.withDefaults; - /** * Allows configuring session management. * @@ -777,17 +775,6 @@ public final class SessionManagementConfigurer> return this; } - /** - * Used to chain back to the {@link SessionManagementConfigurer} - * @return the {@link SessionManagementConfigurer} for further customizations - * @deprecated For removal in 7.0. Use {@link #sessionConcurrency(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public SessionManagementConfigurer and() { - return SessionManagementConfigurer.this; - } - } } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java index 5345ed5dd2..9386fee77e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java @@ -248,7 +248,7 @@ public final class UrlAuthorizationConfigurer> } public H and() { - return UrlAuthorizationConfigurer.this.and(); + return UrlAuthorizationConfigurer.this.getBuilder(); } } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java index 2aae05bbb9..9ed4da02fe 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java @@ -141,18 +141,6 @@ public final class OAuth2ClientConfigurer> return this; } - /** - * Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0 - * Authorization Code Grant. - * @return the {@link AuthorizationCodeGrantConfigurer} - * @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public AuthorizationCodeGrantConfigurer authorizationCodeGrant() { - return this.authorizationCodeGrantConfigurer; - } - /** * Configures the OAuth 2.0 Authorization Code Grant. * @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more @@ -242,17 +230,6 @@ public final class OAuth2ClientConfigurer> return this; } - /** - * Returns the {@link OAuth2ClientConfigurer} for further configuration. - * @return the {@link OAuth2ClientConfigurer} - * @deprecated For removal in 7.0. Use {@link #authorizationCodeGrant(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ClientConfigurer and() { - return OAuth2ClientConfigurer.this; - } - private void init(B builder) { OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider( getAccessTokenResponseClient()); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index d270f55731..c27cb4f2a7 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -104,8 +104,6 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; -import static org.springframework.security.config.Customizer.withDefaults; - /** * An {@link AbstractHttpConfigurer} for OAuth 2.0 Login, which leverages the OAuth 2.0 * Authorization Code Grant Flow. @@ -248,18 +246,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link AuthorizationEndpointConfig} for configuring the Authorization - * Server's Authorization Endpoint. - * @return the {@link AuthorizationEndpointConfig} - * @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public AuthorizationEndpointConfig authorizationEndpoint() { - return this.authorizationEndpointConfig; - } - /** * Configures the Authorization Server's Authorization Endpoint. * @param authorizationEndpointCustomizer the {@link Customizer} to provide more @@ -272,21 +258,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link TokenEndpointConfig} for configuring the Authorization Server's - * Token Endpoint. - * @return the {@link TokenEndpointConfig} - * @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or - * {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public TokenEndpointConfig tokenEndpoint() { - return this.tokenEndpointConfig; - } - /** * Configures the Authorization Server's Token Endpoint. * @param tokenEndpointCustomizer the {@link Customizer} to provide more options for @@ -299,18 +270,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link RedirectionEndpointConfig} for configuring the Client's - * Redirection Endpoint. - * @return the {@link RedirectionEndpointConfig} - * @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public RedirectionEndpointConfig redirectionEndpoint() { - return this.redirectionEndpointConfig; - } - /** * Configures the Client's Redirection Endpoint. * @param redirectionEndpointCustomizer the {@link Customizer} to provide more options @@ -323,21 +282,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link UserInfoEndpointConfig} for configuring the Authorization - * Server's UserInfo Endpoint. - * @return the {@link UserInfoEndpointConfig} - * @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)} or - * {@code userInfoEndpoint(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public UserInfoEndpointConfig userInfoEndpoint() { - return this.userInfoEndpointConfig; - } - /** * Configures the Authorization Server's UserInfo Endpoint. * @param userInfoEndpointCustomizer the {@link Customizer} to provide more options @@ -726,17 +670,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - * @deprecated For removal in 7.0. Use {@link #authorizationEndpoint(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - } /** @@ -763,20 +696,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - * @deprecated For removal in 7.0. Use {@link #tokenEndpoint(Customizer)} or - * {@code tokenEndpoint(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - } /** @@ -801,17 +720,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - * @deprecated For removal in 7.0. Use {@link #redirectionEndpoint(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - } /** @@ -866,17 +774,6 @@ public final class OAuth2LoginConfigurer> return this; } - /** - * Returns the {@link OAuth2LoginConfigurer} for further configuration. - * @return the {@link OAuth2LoginConfigurer} - * @deprecated For removal in 7.0. Use {@link #userInfoEndpoint(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginConfigurer and() { - return OAuth2LoginConfigurer.this; - } - } private static class OidcAuthenticationRequestChecker implements AuthenticationProvider { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcLogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcLogoutConfigurer.java index 1095350dc5..36361600d5 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcLogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OidcLogoutConfigurer.java @@ -111,11 +111,6 @@ public final class OidcLogoutConfigurer> return this; } - @Deprecated(forRemoval = true, since = "6.2") - public B and() { - return getBuilder(); - } - @Override public void configure(B builder) throws Exception { if (this.backChannel != null) { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java index 5bb6fdcbc4..209ba03007 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java @@ -214,20 +214,6 @@ public final class OAuth2ResourceServerConfigurerdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public JwtConfigurer jwt() { - if (this.jwtConfigurer == null) { - this.jwtConfigurer = new JwtConfigurer(this.context); - } - return this.jwtConfigurer; - } - /** * Enables Jwt-encoded bearer token support. * @param jwtCustomizer the {@link Customizer} to provide more options for the @@ -242,21 +228,6 @@ public final class OAuth2ResourceServerConfigurerdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OpaqueTokenConfigurer opaqueToken() { - if (this.opaqueTokenConfigurer == null) { - this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context); - } - return this.opaqueTokenConfigurer; - } - /** * Enables opaque bearer token support. * @param opaqueTokenCustomizer the {@link Customizer} to provide more options for the @@ -441,17 +412,6 @@ public final class OAuth2ResourceServerConfigurerdocumentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ResourceServerConfigurer and() { - return OAuth2ResourceServerConfigurer.this; - } - Converter getJwtAuthenticationConverter() { if (this.jwtAuthenticationConverter == null) { if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java index 22358ea3a2..7ae92aafca 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java @@ -71,8 +71,6 @@ import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.ParameterRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; -import static org.springframework.security.config.Customizer.withDefaults; - /** * Adds SAML 2.0 logout support. * @@ -179,20 +177,6 @@ public final class Saml2LogoutConfigurer> return this; } - /** - * Get configurer for SAML 2.0 Logout Request components - * @return the {@link LogoutRequestConfigurer} for further customizations - * @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or - * {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public LogoutRequestConfigurer logoutRequest() { - return this.logoutRequestConfigurer; - } - /** * Configures SAML 2.0 Logout Request components * @param logoutRequestConfigurerCustomizer the {@link Customizer} to provide more @@ -205,20 +189,6 @@ public final class Saml2LogoutConfigurer> return this; } - /** - * Get configurer for SAML 2.0 Logout Response components - * @return the {@link LogoutResponseConfigurer} for further customizations - * @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or - * {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public LogoutResponseConfigurer logoutResponse() { - return this.logoutResponseConfigurer; - } - /** * Configures SAML 2.0 Logout Response components * @param logoutResponseConfigurerCustomizer the {@link Customizer} to provide more @@ -408,18 +378,6 @@ public final class Saml2LogoutConfigurer> return this; } - /** - * @deprecated For removal in 7.0. Use {@link #logoutRequest(Customizer)} or - * {@code logoutRequest(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public Saml2LogoutConfigurer and() { - return Saml2LogoutConfigurer.this; - } - private Saml2LogoutRequestValidator logoutRequestValidator() { if (this.logoutRequestValidator != null) { return this.logoutRequestValidator; @@ -490,18 +448,6 @@ public final class Saml2LogoutConfigurer> return this; } - /** - * @deprecated For removal in 7.0. Use {@link #logoutResponse(Customizer)} or - * {@code logoutResponse(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public Saml2LogoutConfigurer and() { - return Saml2LogoutConfigurer.this; - } - private Saml2LogoutResponseValidator logoutResponseValidator() { if (this.logoutResponseValidator != null) { return this.logoutResponseValidator; From 9fcfacf283532473658a80dffcf6861755b9688f Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:08:17 -0600 Subject: [PATCH 403/504] Use ServerHttpSecurity Lambda DSL in Tests Issue gh-13067 --- .../reactive/EnableWebFluxSecurityTests.java | 4 +- .../server/AuthorizeExchangeSpecTests.java | 27 ++-- .../config/web/server/CorsSpecTests.java | 2 +- .../server/ExceptionHandlingSpecTests.java | 55 +++---- .../config/web/server/FormLoginTests.java | 87 +++++----- .../config/web/server/HeaderSpecTests.java | 121 +++++++------- .../web/server/HttpsRedirectSpecTests.java | 10 +- .../config/web/server/LogoutSpecTests.java | 48 +++--- .../web/server/OAuth2ClientSpecTests.java | 8 +- .../config/web/server/OAuth2LoginTests.java | 57 +++---- .../server/OAuth2ResourceServerSpecTests.java | 153 +++++++++--------- .../server/PasswordManagementSpecTests.java | 12 +- .../config/web/server/RequestCacheTests.java | 23 ++- .../web/server/ServerHttpSecurityTests.java | 99 +++++------- 14 files changed, 325 insertions(+), 381 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java index a2c0a7de2f..7275ebf5d6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java @@ -377,9 +377,7 @@ public class EnableWebFluxSecurityTests { @Bean SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) { http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**")) - .authorizeExchange() - .anyExchange() - .denyAll(); + .authorizeExchange((exchange) -> exchange.anyExchange().denyAll()); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java index 45efb31d88..b4e4839359 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java @@ -35,13 +35,11 @@ public class AuthorizeExchangeSpecTests { @Test public void antMatchersWhenMethodAndPatternsThenDiscriminatesByMethod() { - this.http.csrf() - .disable() - .authorizeExchange() - .pathMatchers(HttpMethod.POST, "/a", "/b") - .denyAll() - .anyExchange() - .permitAll(); + this.http.csrf((csrf) -> csrf.disable()) + .authorizeExchange((authorize) -> authorize.pathMatchers(HttpMethod.POST, "/a", "/b") + .denyAll() + .anyExchange() + .permitAll()); WebTestClient client = buildClient(); // @formatter:off client.get() @@ -65,7 +63,8 @@ public class AuthorizeExchangeSpecTests { @Test public void antMatchersWhenPatternsThenAnyMethod() { - this.http.csrf().disable().authorizeExchange().pathMatchers("/a", "/b").denyAll().anyExchange().permitAll(); + this.http.csrf((csrf) -> csrf.disable()) + .authorizeExchange((authorize) -> authorize.pathMatchers("/a", "/b").denyAll().anyExchange().permitAll()); WebTestClient client = buildClient(); // @formatter:off client.get() @@ -114,25 +113,25 @@ public class AuthorizeExchangeSpecTests { @Test public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() { - this.http.authorizeExchange().pathMatchers("/incomplete"); + this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/incomplete")); assertThatIllegalStateException() - .isThrownBy(() -> this.http.authorizeExchange().pathMatchers("/throws-exception")); + .isThrownBy(() -> this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/throws-exception"))); } @Test public void anyExchangeWhenFollowedByMatcherThenThrowsException() { assertThatIllegalStateException().isThrownBy(() -> // @formatter:off - this.http.authorizeExchange() - .anyExchange().denyAll() - .pathMatchers("/never-reached") + this.http.authorizeExchange((exchange) -> exchange + .anyExchange().denyAll() + .pathMatchers("/never-reached")) // @formatter:on ); } @Test public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() { - this.http.authorizeExchange().pathMatchers("/incomplete"); + this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/incomplete")); assertThatIllegalStateException().isThrownBy(this.http::build); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java index 3ae317d751..1aa6d5ff92 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/CorsSpecTests.java @@ -73,7 +73,7 @@ public class CorsSpecTests { @Test public void corsWhenEnabledThenAccessControlAllowOriginAndSecurityHeaders() { givenGetCorsConfigurationWillReturnWildcard(); - this.http.cors().configurationSource(this.source); + this.http.cors((cors) -> cors.configurationSource(this.source)); this.expectedHeaders.set("Access-Control-Allow-Origin", "*"); this.expectedHeaders.set("X-Frame-Options", "DENY"); assertHeaders(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java index f360ed40bb..cc38649dc3 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java @@ -19,6 +19,7 @@ package org.springframework.security.config.web.server; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; import org.springframework.security.web.server.SecurityWebFilterChain; @@ -42,12 +43,11 @@ public class ExceptionHandlingSpecTests { public void defaultAuthenticationEntryPoint() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .csrf().disable() - .authorizeExchange() - .anyExchange().authenticated() - .and() - .exceptionHandling().and() - .build(); + .csrf((csrf) -> csrf.disable()) + .authorizeExchange((authorize) -> authorize + .anyExchange().authenticated()) + .exceptionHandling(withDefaults()) + .build(); WebTestClient client = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -83,14 +83,12 @@ public class ExceptionHandlingSpecTests { public void customAuthenticationEntryPoint() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .csrf().disable() - .authorizeExchange() - .anyExchange().authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(redirectServerAuthenticationEntryPoint("/auth")) - .and() - .build(); + .csrf((csrf) -> csrf.disable()) + .authorizeExchange((authorize) -> authorize + .anyExchange().authenticated()) + .exceptionHandling((handling) -> handling + .authenticationEntryPoint(redirectServerAuthenticationEntryPoint("/auth"))) + .build(); WebTestClient client = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -128,13 +126,12 @@ public class ExceptionHandlingSpecTests { public void defaultAccessDeniedHandler() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .csrf().disable() - .httpBasic().and() - .authorizeExchange() - .anyExchange().hasRole("ADMIN") - .and() - .exceptionHandling().and() - .build(); + .csrf((csrf) -> csrf.disable()) + .httpBasic(Customizer.withDefaults()) + .authorizeExchange((exchange) -> exchange + .anyExchange().hasRole("ADMIN")) + .exceptionHandling(withDefaults()) + .build(); WebTestClient client = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -171,15 +168,13 @@ public class ExceptionHandlingSpecTests { public void customAccessDeniedHandler() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .csrf().disable() - .httpBasic().and() - .authorizeExchange() - .anyExchange().hasRole("ADMIN") - .and() - .exceptionHandling() - .accessDeniedHandler(httpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST)) - .and() - .build(); + .csrf((csrf) -> csrf.disable()) + .httpBasic(Customizer.withDefaults()) + .authorizeExchange((exchange) -> exchange + .anyExchange().hasRole("ADMIN")) + .exceptionHandling((handling) -> handling + .accessDeniedHandler(httpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))) + .build(); WebTestClient client = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java index d504ea17f1..1fef14dbac 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java @@ -69,12 +69,10 @@ public class FormLoginTests { public void defaultLoginPage() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin() - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -129,14 +127,12 @@ public class FormLoginTests { public void customLoginPage() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .pathMatchers("/login").permitAll() - .anyExchange().authenticated() - .and() - .formLogin() - .loginPage("/login") - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .pathMatchers("/login").permitAll() + .anyExchange().authenticated()) + .formLogin((login) -> login + .loginPage("/login")) + .build(); WebTestClient webTestClient = WebTestClient .bindToController(new CustomLoginPageController(), new WebTestClientBuilder.Http200RestController()) .webFilter(new WebFilterChainProxy(securityWebFilter)) @@ -189,14 +185,12 @@ public class FormLoginTests { public void formLoginWhenCustomAuthenticationFailureHandlerThenUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .pathMatchers("/login", "/failure").permitAll() - .anyExchange().authenticated() - .and() - .formLogin() - .authenticationFailureHandler(new RedirectServerAuthenticationFailureHandler("/failure")) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .pathMatchers("/login", "/failure").permitAll() + .anyExchange().authenticated()) + .formLogin((login) -> login + .authenticationFailureHandler(new RedirectServerAuthenticationFailureHandler("/failure"))) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -218,14 +212,12 @@ public class FormLoginTests { public void formLoginWhenCustomRequiresAuthenticationMatcherThenUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .pathMatchers("/login", "/sign-in").permitAll() - .anyExchange().authenticated() - .and() - .formLogin() - .requiresAuthenticationMatcher(new PathPatternParserServerWebExchangeMatcher("/sign-in")) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .pathMatchers("/login", "/sign-in").permitAll() + .anyExchange().authenticated()) + .formLogin((login) -> login + .requiresAuthenticationMatcher(new PathPatternParserServerWebExchangeMatcher("/sign-in"))) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -241,13 +233,11 @@ public class FormLoginTests { public void authenticationSuccess() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin() - .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/custom")) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin((login) -> login + .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/custom"))) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -275,11 +265,10 @@ public class FormLoginTests { .willReturn(Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_USER", "ROLE_ADMIN"))); // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authenticationManager(defaultAuthenticationManager) - .formLogin() - .authenticationManager(customAuthenticationManager) - .and() - .build(); + .authenticationManager(defaultAuthenticationManager) + .formLogin((login) -> login + .authenticationManager(customAuthenticationManager)) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -309,14 +298,12 @@ public class FormLoginTests { given(formLoginSecContextRepository.load(any())).willReturn(authentication(token)); // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .securityContextRepository(defaultSecContextRepository) - .formLogin() - .securityContextRepository(formLoginSecContextRepository) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .securityContextRepository(defaultSecContextRepository) + .formLogin((login) -> login + .securityContextRepository(formLoginSecContextRepository)) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java index 486cf40798..90ebcc1a2f 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import org.springframework.http.HttpHeaders; +import org.springframework.security.config.Customizer; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter; import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter; @@ -79,7 +80,7 @@ public class HeaderSpecTests { @Test public void headersWhenDisableThenNoSecurityHeaders() { new HashSet<>(this.expectedHeaders.headerNames()).forEach(this::expectHeaderNamesNotPresent); - this.http.headers().disable(); + this.http.headers((headers) -> headers.disable()); assertHeaders(); } @@ -92,13 +93,13 @@ public class HeaderSpecTests { @Test public void headersWhenDisableAndInvokedExplicitlyThenDefautsUsed() { - this.http.headers().disable().headers(); + this.http.headers((headers) -> headers.disable().headers(Customizer.withDefaults())); assertHeaders(); } @Test public void headersWhenDefaultsThenAllDefaultsWritten() { - this.http.headers(); + this.http.headers(withDefaults()); assertHeaders(); } @@ -111,7 +112,7 @@ public class HeaderSpecTests { @Test public void headersWhenCacheDisableThenCacheNotWritten() { expectHeaderNamesNotPresent(HttpHeaders.CACHE_CONTROL, HttpHeaders.PRAGMA, HttpHeaders.EXPIRES); - this.http.headers().cache().disable(); + this.http.headers((headers) -> headers.cache((cache) -> cache.disable())); assertHeaders(); } @@ -129,7 +130,7 @@ public class HeaderSpecTests { @Test public void headersWhenContentOptionsDisableThenContentTypeOptionsNotWritten() { expectHeaderNamesNotPresent(ContentTypeOptionsServerHttpHeadersWriter.X_CONTENT_OPTIONS); - this.http.headers().contentTypeOptions().disable(); + this.http.headers((headers) -> headers.contentTypeOptions((options) -> options.disable())); assertHeaders(); } @@ -148,7 +149,7 @@ public class HeaderSpecTests { @Test public void headersWhenHstsDisableThenHstsNotWritten() { expectHeaderNamesNotPresent(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY); - this.http.headers().hsts().disable(); + this.http.headers((headers) -> headers.hsts((hsts) -> hsts.disable())); assertHeaders(); } @@ -169,10 +170,10 @@ public class HeaderSpecTests { this.expectedHeaders.add(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=60"); // @formatter:off - this.http.headers() - .hsts() - .maxAge(Duration.ofSeconds(60)) - .includeSubdomains(false); + this.http.headers((headers) -> headers + .hsts((hsts) -> hsts + .maxAge(Duration.ofSeconds(60)) + .includeSubdomains(false))); // @formatter:on assertHeaders(); } @@ -200,10 +201,10 @@ public class HeaderSpecTests { this.expectedHeaders.add(StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=60 ; includeSubDomains ; preload"); // @formatter:off - this.http.headers() - .hsts() - .maxAge(Duration.ofSeconds(60)) - .preload(true); + this.http.headers((headers) -> headers + .hsts((hsts) -> hsts + .maxAge(Duration.ofSeconds(60)) + .preload(true))); // @formatter:on assertHeaders(); } @@ -228,8 +229,8 @@ public class HeaderSpecTests { public void headersWhenFrameOptionsDisableThenFrameOptionsNotWritten() { expectHeaderNamesNotPresent(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS); // @formatter:off - this.http.headers() - .frameOptions().disable(); + this.http.headers((headers) -> headers + .frameOptions((options) -> options.disable())); // @formatter:on assertHeaders(); } @@ -251,9 +252,9 @@ public class HeaderSpecTests { public void headersWhenFrameOptionsModeThenFrameOptionsCustomMode() { this.expectedHeaders.set(XFrameOptionsServerHttpHeadersWriter.X_FRAME_OPTIONS, "SAMEORIGIN"); // @formatter:off - this.http.headers() - .frameOptions() - .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN); + this.http.headers((headers) -> headers + .frameOptions((frameOptions) -> frameOptions + .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN))); // @formatter:on assertHeaders(); } @@ -275,8 +276,8 @@ public class HeaderSpecTests { public void headersWhenXssProtectionDisableThenXssProtectionNotWritten() { expectHeaderNamesNotPresent("X-Xss-Protection"); // @formatter:off - this.http.headers() - .xssProtection().disable(); + this.http.headers((headers) -> headers + .xssProtection((xss) -> xss.disable())); // @formatter:on assertHeaders(); } @@ -298,9 +299,9 @@ public class HeaderSpecTests { public void headersWhenXssProtectionValueDisabledThenXssProtectionWritten() { this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0"); // @formatter:off - this.http.headers() - .xssProtection() - .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED); + this.http.headers((headers) -> headers + .xssProtection((xss) -> xss + .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED))); // @formatter:on assertHeaders(); } @@ -309,9 +310,9 @@ public class HeaderSpecTests { public void headersWhenXssProtectionValueEnabledThenXssProtectionWritten() { this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1"); // @formatter:off - this.http.headers() - .xssProtection() - .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED); + this.http.headers((headers) -> headers + .xssProtection((xss) -> xss + .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED))); // @formatter:on assertHeaders(); } @@ -320,9 +321,9 @@ public class HeaderSpecTests { public void headersWhenXssProtectionValueEnabledModeBlockThenXssProtectionWritten() { this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "1; mode=block"); // @formatter:off - this.http.headers() - .xssProtection() - .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK); + this.http.headers((headers) -> headers + .xssProtection((xss) -> xss + .headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.ENABLED_MODE_BLOCK))); // @formatter:on assertHeaders(); } @@ -331,10 +332,10 @@ public class HeaderSpecTests { public void headersWhenXssProtectionValueDisabledInLambdaThenXssProtectionWritten() { this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0"); // @formatter:off - this.http.headers() - .xssProtection((xssProtection) -> - xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED) - ); + this.http.headers((headers) -> headers + .xssProtection((xssProtection) -> + xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED) + )); // @formatter:on assertHeaders(); } @@ -344,8 +345,8 @@ public class HeaderSpecTests { String policyDirectives = "Feature-Policy"; this.expectedHeaders.add(FeaturePolicyServerHttpHeadersWriter.FEATURE_POLICY, policyDirectives); // @formatter:off - this.http.headers() - .featurePolicy(policyDirectives); + this.http.headers((headers) -> headers + .featurePolicy(policyDirectives)); // @formatter:on assertHeaders(); } @@ -356,8 +357,8 @@ public class HeaderSpecTests { this.expectedHeaders.add(ContentSecurityPolicyServerHttpHeadersWriter.CONTENT_SECURITY_POLICY, policyDirectives); // @formatter:off - this.http.headers() - .contentSecurityPolicy(policyDirectives); + this.http.headers((headers) -> headers + .contentSecurityPolicy((csp) -> csp.policyDirectives(policyDirectives))); // @formatter:on assertHeaders(); } @@ -395,8 +396,8 @@ public class HeaderSpecTests { this.expectedHeaders.add(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY, ReferrerPolicy.NO_REFERRER.getPolicy()); // @formatter:off - this.http.headers() - .referrerPolicy(); + this.http.headers((headers) -> headers + .referrerPolicy(Customizer.withDefaults())); // @formatter:on assertHeaders(); } @@ -419,8 +420,8 @@ public class HeaderSpecTests { this.expectedHeaders.add(ReferrerPolicyServerHttpHeadersWriter.REFERRER_POLICY, ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE.getPolicy()); // @formatter:off - this.http.headers() - .referrerPolicy(ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE); + this.http.headers((headers) -> headers + .referrerPolicy((referrer) -> referrer.policy(ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE))); // @formatter:on assertHeaders(); } @@ -463,15 +464,13 @@ public class HeaderSpecTests { this.expectedHeaders.add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY, CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN.getPolicy()); // @formatter:off - this.http.headers() - .crossOriginOpenerPolicy() - .policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS) - .and() - .crossOriginEmbedderPolicy() - .policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP) - .and() - .crossOriginResourcePolicy() - .policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN); + this.http.headers((headers) -> headers + .crossOriginOpenerPolicy((opener) -> opener + .policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS)) + .crossOriginEmbedderPolicy((embedder) -> embedder + .policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)) + .crossOriginResourcePolicy((resource) -> resource + .policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN))); // @formatter:on assertHeaders(); } @@ -486,16 +485,16 @@ public class HeaderSpecTests { this.expectedHeaders.add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY, CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN.getPolicy()); // @formatter:off - this.http.headers() - .crossOriginOpenerPolicy((policy) -> policy - .policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS) - ) - .crossOriginEmbedderPolicy((policy) -> policy - .policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP) - ) - .crossOriginResourcePolicy((policy) -> policy - .policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN) - ); + this.http.headers((headers) -> headers + .crossOriginOpenerPolicy((policy) -> policy + .policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS) + ) + .crossOriginEmbedderPolicy((policy) -> policy + .policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP) + ) + .crossOriginResourcePolicy((policy) -> policy + .policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN) + )); // @formatter:on assertHeaders(); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java index 55d5ec7059..f169f3b843 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java @@ -162,7 +162,7 @@ public class HttpsRedirectSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .redirectToHttps(); + .redirectToHttps(withDefaults()); // @formatter:on return http.build(); } @@ -194,8 +194,8 @@ public class HttpsRedirectSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .redirectToHttps() - .httpsRedirectWhen(new PathPatternParserServerWebExchangeMatcher("/secure")); + .redirectToHttps((https) -> https + .httpsRedirectWhen(new PathPatternParserServerWebExchangeMatcher("/secure"))); // @formatter:on return http.build(); } @@ -230,8 +230,8 @@ public class HttpsRedirectSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .redirectToHttps() - .portMapper(portMapper()); + .redirectToHttps((https) -> https + .portMapper(portMapper())); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java index a9f633b37a..22912a2a1d 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java @@ -44,12 +44,10 @@ public class LogoutSpecTests { public void defaultLogout() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin() - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -80,14 +78,12 @@ public class LogoutSpecTests { public void customLogout() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin().and() - .logout() - .requiresLogout(ServerWebExchangeMatchers.pathMatchers("/custom-logout")) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .logout((logout) -> logout + .requiresLogout(ServerWebExchangeMatchers.pathMatchers("/custom-logout"))) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); @@ -155,12 +151,11 @@ public class LogoutSpecTests { public void logoutWhenDisabledThenDefaultLogoutPageDoesNotExist() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin().and() - .logout().disable() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .logout((logout) -> logout.disable()) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToControllerAndWebFilters(HomeController.class, securityWebFilter) .build(); @@ -188,13 +183,12 @@ public class LogoutSpecTests { repository.setSpringSecurityContextAttrName("CUSTOM_CONTEXT_ATTR"); // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .securityContextRepository(repository) - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin().and() - .logout().and() - .build(); + .securityContextRepository(repository) + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .logout(withDefaults()) + .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java index 0bd8391d71..b8af150999 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java @@ -73,6 +73,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -289,7 +290,7 @@ public class OAuth2ClientSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .oauth2Client(); + .oauth2Client(withDefaults()); // @formatter:on return http.build(); } @@ -348,12 +349,11 @@ public class OAuth2ClientSpecTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .oauth2Client() + .oauth2Client((client) -> client .authenticationConverter(this.authenticationConverter) .authenticationManager(this.manager) .authorizationRequestRepository(this.authorizationRequestRepository) - .authorizationRequestResolver(this.resolver) - .and() + .authorizationRequestResolver(this.resolver)) .requestCache((c) -> c.requestCache(this.requestCache)); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java index 4597d3e786..e4a6ad711f 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java @@ -122,6 +122,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.springframework.security.config.Customizer.withDefaults; /** * @author Rob Winch @@ -825,11 +826,10 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .requestCache() - .requestCache(this.requestCache) - .and() - .oauth2Login() - .authorizationRequestRepository(this.authorizationRequestRepository); + .requestCache((cache) -> cache + .requestCache(this.requestCache)) + .oauth2Login((login) -> login + .authorizationRequestRepository(this.authorizationRequestRepository)); // @formatter:on return http.build(); } @@ -863,12 +863,10 @@ public class OAuth2LoginTests { http.authenticationManager(authenticationManager); // @formatter:off http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .oauth2Login() - .and() - .formLogin(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .oauth2Login(withDefaults()) + .formLogin(withDefaults()); // @formatter:on return http.build(); } @@ -887,12 +885,10 @@ public class OAuth2LoginTests { http.authenticationManager(authenticationManager); // @formatter:off http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .oauth2Login() - .and() - .httpBasic(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .oauth2Login(withDefaults()) + .httpBasic(withDefaults()); // @formatter:on return http.build(); } @@ -958,16 +954,15 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .oauth2Login() + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .oauth2Login((login) -> login .authenticationConverter(this.authenticationConverter) .authenticationManager(this.manager) .authenticationMatcher(this.matcher) .authorizationRequestResolver(this.resolver) .authenticationSuccessHandler(this.successHandler) - .authenticationFailureHandler(this.failureHandler); + .authenticationFailureHandler(this.failureHandler)); // @formatter:on return http.build(); } @@ -1031,13 +1026,12 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .oauth2Login() + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .oauth2Login((login) -> login .authenticationConverter(this.authenticationConverter) .authenticationManager(authenticationManager()) - .securityContextRepository(this.securityContextRepository); + .securityContextRepository(this.securityContextRepository)); return http.build(); // @formatter:on } @@ -1102,14 +1096,13 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .csrf().disable() - .logout() + .csrf((csrf) -> csrf.disable()) + .logout((logout) -> logout // avoid using mock ServerSecurityContextRepository for logout .logoutHandler(new SecurityContextServerLogoutHandler()) .logoutSuccessHandler( - new OidcClientInitiatedServerLogoutSuccessHandler( - new InMemoryReactiveClientRegistrationRepository(this.withLogout))) - .and() + new OidcClientInitiatedServerLogoutSuccessHandler( + new InMemoryReactiveClientRegistrationRepository(this.withLogout)))) .securityContextRepository(this.repository); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java index bf31b46d33..2a62230c76 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java @@ -55,6 +55,7 @@ import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver; import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; @@ -463,9 +464,10 @@ public class OAuth2ResourceServerSpecTests { ReactiveJwtDecoder beanWiredJwtDecoder = mock(ReactiveJwtDecoder.class); ReactiveJwtDecoder dslWiredJwtDecoder = mock(ReactiveJwtDecoder.class); context.registerBean(ReactiveJwtDecoder.class, () -> beanWiredJwtDecoder); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - jwt.jwtDecoder(dslWiredJwtDecoder); - assertThat(jwt.getJwtDecoder()).isEqualTo(dslWiredJwtDecoder); + http.oauth2ResourceServer((server) -> server.jwt((jwt) -> { + jwt.jwtDecoder(dslWiredJwtDecoder); + assertThat(jwt.getJwtDecoder()).isEqualTo(dslWiredJwtDecoder); + })); } @Test @@ -477,9 +479,10 @@ public class OAuth2ResourceServerSpecTests { ReactiveJwtDecoder dslWiredJwtDecoder = mock(ReactiveJwtDecoder.class); context.registerBean("firstJwtDecoder", ReactiveJwtDecoder.class, () -> beanWiredJwtDecoder); context.registerBean("secondJwtDecoder", ReactiveJwtDecoder.class, () -> beanWiredJwtDecoder); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - jwt.jwtDecoder(dslWiredJwtDecoder); - assertThat(jwt.getJwtDecoder()).isEqualTo(dslWiredJwtDecoder); + http.oauth2ResourceServer((server) -> server.jwt((jwt) -> { + jwt.jwtDecoder(dslWiredJwtDecoder); + assertThat(jwt.getJwtDecoder()).isEqualTo(dslWiredJwtDecoder); + })); } @Test @@ -490,8 +493,9 @@ public class OAuth2ResourceServerSpecTests { ReactiveJwtDecoder beanWiredJwtDecoder = mock(ReactiveJwtDecoder.class); context.registerBean("firstJwtDecoder", ReactiveJwtDecoder.class, () -> beanWiredJwtDecoder); context.registerBean("secondJwtDecoder", ReactiveJwtDecoder.class, () -> beanWiredJwtDecoder); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(() -> jwt.getJwtDecoder()); + http.oauth2ResourceServer( + (server) -> server.jwt((jwt) -> assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) + .isThrownBy(jwt::getJwtDecoder))); } @Test @@ -499,8 +503,9 @@ public class OAuth2ResourceServerSpecTests { GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext(); ServerHttpSecurity http = new ServerHttpSecurity(); http.setApplicationContext(context); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> jwt.getJwtDecoder()); + http.oauth2ResourceServer( + (server) -> server.jwt((jwt) -> assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(jwt::getJwtDecoder))); } @Test @@ -511,9 +516,10 @@ public class OAuth2ResourceServerSpecTests { ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); ReactiveJwtAuthenticationConverter dslWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); context.registerBean(ReactiveJwtAuthenticationConverter.class, () -> beanWiredJwtAuthenticationConverter); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter); - assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter); + http.oauth2ResourceServer((server) -> server.jwt((jwt) -> { + jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter); + assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter); + })); } @Test @@ -527,9 +533,10 @@ public class OAuth2ResourceServerSpecTests { () -> beanWiredJwtAuthenticationConverter); context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class, () -> beanWiredJwtAuthenticationConverter); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter); - assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter); + http.oauth2ResourceServer((server) -> server.jwt((jwt) -> { + jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter); + assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter); + })); } @Test @@ -542,8 +549,9 @@ public class OAuth2ResourceServerSpecTests { () -> beanWiredJwtAuthenticationConverter); context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class, () -> beanWiredJwtAuthenticationConverter); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(jwt::getJwtAuthenticationConverter); + http.oauth2ResourceServer( + (server) -> server.jwt((jwt) -> assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) + .isThrownBy(jwt::getJwtAuthenticationConverter))); } @Test @@ -551,8 +559,8 @@ public class OAuth2ResourceServerSpecTests { GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext(); ServerHttpSecurity http = new ServerHttpSecurity(); http.setApplicationContext(context); - ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt(); - assertThat(jwt.getJwtAuthenticationConverter()).isInstanceOf(ReactiveJwtAuthenticationConverter.class); + http.oauth2ResourceServer((server) -> server.jwt((jwt) -> assertThat(jwt.getJwtAuthenticationConverter()) + .isInstanceOf(ReactiveJwtAuthenticationConverter.class))); } @Test @@ -674,12 +682,10 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().hasAuthority("SCOPE_message:read") - .and() - .oauth2ResourceServer() - .jwt() - .publicKey(publicKey()); + .authorizeExchange((exchange) -> exchange + .anyExchange().hasAuthority("SCOPE_message:read")) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.publicKey(publicKey()))); // @formatter:on return http.build(); } @@ -724,12 +730,10 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().hasAuthority("SCOPE_message:read") - .and() - .oauth2ResourceServer() - .jwt() - .publicKey(this.key); + .authorizeExchange((exchange) -> exchange + .anyExchange().hasAuthority("SCOPE_message:read")) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.publicKey(this.key))); // @formatter:on return http.build(); } @@ -748,9 +752,8 @@ public class OAuth2ResourceServerSpecTests { String jwkSetUri = mockWebServer().url("/.well-known/jwks.json").toString(); // @formatter:off http - .oauth2ResourceServer() - .jwt() - .jwkSetUri(jwkSetUri); + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.jwkSetUri(jwkSetUri))); // @formatter:on return http.build(); } @@ -813,8 +816,8 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .oauth2ResourceServer() - .jwt(); + .oauth2ResourceServer((server) -> server + .jwt(Customizer.withDefaults())); // @formatter:on return http.build(); } @@ -835,12 +838,10 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain authorization(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().denyAll() - .and() - .oauth2ResourceServer() - .jwt() - .publicKey(publicKey()); + .authorizeExchange((exchange) -> exchange + .anyExchange().denyAll()) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.publicKey(publicKey()))); // @formatter:on return http.build(); } @@ -856,9 +857,8 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .oauth2ResourceServer() - .jwt() - .authenticationManager(authenticationManager()); + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt.authenticationManager(authenticationManager()))); // @formatter:on return http.build(); } @@ -906,11 +906,10 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .pathMatchers("/*/message/**").hasAnyAuthority("SCOPE_message:read") - .and() - .oauth2ResourceServer() - .authenticationManagerResolver(authenticationManagerResolver()); + .authorizeExchange((exchange) -> exchange + .pathMatchers("/*/message/**").hasAnyAuthority("SCOPE_message:read")) + .oauth2ResourceServer((server) -> server + .authenticationManagerResolver(authenticationManagerResolver())); // @formatter:on return http.build(); } @@ -965,13 +964,11 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().hasAuthority("SCOPE_message:read") - .and() - .oauth2ResourceServer() + .authorizeExchange((exchange) -> exchange + .anyExchange().hasAuthority("SCOPE_message:read")) + .oauth2ResourceServer((server) -> server .bearerTokenConverter(bearerTokenAuthenticationConverter()) - .jwt() - .publicKey(publicKey()); + .jwt((jwt) -> jwt.publicKey(publicKey()))); // @formatter:on return http.build(); } @@ -993,13 +990,12 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().hasAuthority("message:read") - .and() - .oauth2ResourceServer() - .jwt() + .authorizeExchange((exchange) -> exchange + .anyExchange().hasAuthority("message:read")) + .oauth2ResourceServer((server) -> server + .jwt((jwt) -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter()) - .publicKey(publicKey()); + .publicKey(publicKey()))); // @formatter:on return http.build(); } @@ -1025,15 +1021,13 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() + .authorizeExchange((exchange) -> exchange .pathMatchers("/authenticated").authenticated() - .pathMatchers("/unobtainable").hasAuthority("unobtainable") - .and() - .oauth2ResourceServer() + .pathMatchers("/unobtainable").hasAuthority("unobtainable")) + .oauth2ResourceServer((server) -> server .accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED)) .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.I_AM_A_TEAPOT)) - .jwt() - .publicKey(publicKey()); + .jwt((jwt) -> jwt.publicKey(publicKey()))); // @formatter:on return http.build(); } @@ -1052,10 +1046,10 @@ public class OAuth2ResourceServerSpecTests { String introspectionUri = mockWebServer().url("/introspect").toString(); // @formatter:off http - .oauth2ResourceServer() - .opaqueToken() + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken .introspectionUri(introspectionUri) - .introspectionClientCredentials("client", "secret"); + .introspectionClientCredentials("client", "secret"))); // @formatter:on return http.build(); } @@ -1117,12 +1111,11 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .oauth2ResourceServer() + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .oauth2ResourceServer((server) -> server .authenticationManagerResolver(mock(ReactiveAuthenticationManagerResolver.class)) - .opaqueToken(); + .opaqueToken(Customizer.withDefaults())); // @formatter:on return http.build(); } @@ -1141,11 +1134,11 @@ public class OAuth2ResourceServerSpecTests { String introspectionUri = mockWebServer().url("/introspect").toString(); // @formatter:off http - .oauth2ResourceServer() - .opaqueToken() + .oauth2ResourceServer((server) -> server + .opaqueToken((opaqueToken) -> opaqueToken .introspectionUri(introspectionUri) .introspectionClientCredentials("client", "secret") - .authenticationConverter(authenticationConverter()); + .authenticationConverter(authenticationConverter()))); // @formatter:on return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/PasswordManagementSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/PasswordManagementSpecTests.java index e4e24ff184..d3bb811a5d 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/PasswordManagementSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/PasswordManagementSpecTests.java @@ -19,6 +19,7 @@ package org.springframework.security.config.web.server; import org.apache.http.HttpHeaders; import org.junit.jupiter.api.Test; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder; import org.springframework.security.config.web.server.ServerHttpSecurity.PasswordManagementSpec; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; @@ -37,7 +38,7 @@ public class PasswordManagementSpecTests { @Test public void whenChangePasswordPageNotSetThenDefaultChangePasswordPageUsed() { - this.http.passwordManagement(); + this.http.passwordManagement(Customizer.withDefaults()); WebTestClient client = buildClient(); client.get() @@ -70,19 +71,22 @@ public class PasswordManagementSpecTests { @Test public void whenSettingNullChangePasswordPage() { - assertThatIllegalArgumentException().isThrownBy(() -> this.http.passwordManagement().changePasswordPage(null)) + assertThatIllegalArgumentException() + .isThrownBy(() -> this.http.passwordManagement((password) -> password.changePasswordPage(null))) .withMessage("changePasswordPage cannot be empty"); } @Test public void whenSettingEmptyChangePasswordPage() { - assertThatIllegalArgumentException().isThrownBy(() -> this.http.passwordManagement().changePasswordPage("")) + assertThatIllegalArgumentException() + .isThrownBy(() -> this.http.passwordManagement((password) -> password.changePasswordPage(""))) .withMessage("changePasswordPage cannot be empty"); } @Test public void whenSettingBlankChangePasswordPage() { - assertThatIllegalArgumentException().isThrownBy(() -> this.http.passwordManagement().changePasswordPage(" ")) + assertThatIllegalArgumentException() + .isThrownBy(() -> this.http.passwordManagement((password) -> password.changePasswordPage(" "))) .withMessage("changePasswordPage cannot be empty"); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java b/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java index eab884ad5a..de9c5d4427 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java @@ -49,11 +49,10 @@ public class RequestCacheTests { public void defaultFormLoginRequestCache() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin().and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .build(); WebTestClient webTestClient = WebTestClient .bindToController(new SecuredPageController(), new WebTestClientBuilder.Http200RestController()) .webFilter(new WebFilterChainProxy(securityWebFilter)) @@ -76,14 +75,12 @@ public class RequestCacheTests { public void requestCacheNoOp() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange() - .anyExchange().authenticated() - .and() - .formLogin().and() - .requestCache() - .requestCache(NoOpServerRequestCache.getInstance()) - .and() - .build(); + .authorizeExchange((exchange) -> exchange + .anyExchange().authenticated()) + .formLogin(withDefaults()) + .requestCache((cache) -> cache + .requestCache(NoOpServerRequestCache.getInstance())) + .build(); WebTestClient webTestClient = WebTestClient .bindToController(new SecuredPageController(), new WebTestClientBuilder.Http200RestController()) .webFilter(new WebFilterChainProxy(securityWebFilter)) diff --git a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java index a2ff87abd0..7521d5925f 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java @@ -146,10 +146,9 @@ public class ServerHttpSecurityTests { public void basic() { given(this.authenticationManager.authenticate(any())) .willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN"))); - this.http.httpBasic(); + this.http.httpBasic(withDefaults()); this.http.authenticationManager(this.authenticationManager); - ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); - authorize.anyExchange().authenticated(); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off EntityExchangeResult result = client.get() @@ -171,10 +170,9 @@ public class ServerHttpSecurityTests { given(this.authenticationManager.authenticate(any())) .willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN"))); this.http.securityContextRepository(new WebSessionServerSecurityContextRepository()); - this.http.httpBasic(); + this.http.httpBasic(withDefaults()); this.http.authenticationManager(this.authenticationManager); - ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); - authorize.anyExchange().authenticated(); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off EntityExchangeResult result = client.get() @@ -193,7 +191,7 @@ public class ServerHttpSecurityTests { @Test public void basicWhenNoCredentialsThenUnauthorized() { - this.http.authorizeExchange().anyExchange().authenticated(); + this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off client.get().uri("/") @@ -208,8 +206,8 @@ public class ServerHttpSecurityTests { public void basicWhenXHRRequestThenUnauthorized() { ServerAuthenticationEntryPoint authenticationEntryPoint = spy( new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)); - this.http.httpBasic().authenticationEntryPoint(authenticationEntryPoint); - this.http.authorizeExchange().anyExchange().authenticated(); + this.http.httpBasic((basic) -> basic.authenticationEntryPoint(authenticationEntryPoint)); + this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off client.get().uri("/") @@ -228,9 +226,9 @@ public class ServerHttpSecurityTests { ReactiveAuthenticationManager authenticationManager = mock(ReactiveAuthenticationManager.class); ServerAuthenticationFailureHandler authenticationFailureHandler = mock( ServerAuthenticationFailureHandler.class); - this.http.httpBasic().authenticationFailureHandler(authenticationFailureHandler); - this.http.httpBasic().authenticationManager(authenticationManager); - this.http.authorizeExchange().anyExchange().authenticated(); + this.http.httpBasic((basic) -> basic.authenticationFailureHandler(authenticationFailureHandler)); + this.http.httpBasic((basic) -> basic.authenticationManager(authenticationManager)); + this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); given(authenticationManager.authenticate(any())) .willReturn(Mono.error(() -> new BadCredentialsException("bad"))); given(authenticationFailureHandler.onAuthenticationFailure(any(), any())).willReturn(Mono.empty()); @@ -261,7 +259,7 @@ public class ServerHttpSecurityTests { @Test public void csrfServerLogoutHandlerNotAppliedIfCsrfIsntEnabled() { - SecurityWebFilterChain securityWebFilterChain = this.http.csrf().disable().build(); + SecurityWebFilterChain securityWebFilterChain = this.http.csrf((csrf) -> csrf.disable()).build(); assertThat(getWebFilter(securityWebFilterChain, CsrfWebFilter.class)).isNotPresent(); Optional logoutHandler = getWebFilter(securityWebFilterChain, LogoutWebFilter.class) .map((logoutWebFilter) -> (ServerLogoutHandler) ReflectionTestUtils.getField(logoutWebFilter, @@ -271,9 +269,8 @@ public class ServerHttpSecurityTests { @Test public void csrfServerLogoutHandlerAppliedIfCsrfIsEnabled() { - SecurityWebFilterChain securityWebFilterChain = this.http.csrf() - .csrfTokenRepository(this.csrfTokenRepository) - .and() + SecurityWebFilterChain securityWebFilterChain = this.http + .csrf((csrf) -> csrf.csrfTokenRepository(this.csrfTokenRepository)) .build(); assertThat(getWebFilter(securityWebFilterChain, CsrfWebFilter.class)).get() .extracting((csrfWebFilter) -> ReflectionTestUtils.getField(csrfWebFilter, "csrfTokenRepository")) @@ -328,8 +325,8 @@ public class ServerHttpSecurityTests { public void anonymous() { // @formatter:off SecurityWebFilterChain securityFilterChain = this.http - .anonymous().and() - .build(); + .anonymous(withDefaults()) + .build(); WebTestClient client = WebTestClientBuilder .bindToControllerAndWebFilters(AnonymousAuthenticationWebFilterTests.HttpMeController.class, securityFilterChain) .build(); @@ -360,10 +357,9 @@ public class ServerHttpSecurityTests { public void basicWithAnonymous() { given(this.authenticationManager.authenticate(any())) .willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN"))); - this.http.httpBasic().and().anonymous(); + this.http.httpBasic(withDefaults()).anonymous(withDefaults()); this.http.authenticationManager(this.authenticationManager); - ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); - authorize.anyExchange().hasAuthority("ROLE_ADMIN"); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().hasAuthority("ROLE_ADMIN")); WebTestClient client = buildClient(); // @formatter:off EntityExchangeResult result = client.get() @@ -384,10 +380,9 @@ public class ServerHttpSecurityTests { this.http.securityContextRepository(new WebSessionServerSecurityContextRepository()); HttpBasicServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint(); authenticationEntryPoint.setRealm("myrealm"); - this.http.httpBasic().authenticationEntryPoint(authenticationEntryPoint); + this.http.httpBasic((basic) -> basic.authenticationEntryPoint(authenticationEntryPoint)); this.http.authenticationManager(this.authenticationManager); - ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); - authorize.anyExchange().authenticated(); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off EntityExchangeResult result = client.get() @@ -408,8 +403,7 @@ public class ServerHttpSecurityTests { authenticationEntryPoint.setRealm("myrealm"); this.http.httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(authenticationEntryPoint)); this.http.authenticationManager(this.authenticationManager); - ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); - authorize.anyExchange().authenticated(); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off EntityExchangeResult result = client.get() @@ -430,10 +424,9 @@ public class ServerHttpSecurityTests { .willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN"))); // @formatter:off SecurityWebFilterChain securityFilterChain = this.http - .httpBasic() - .authenticationManager(customAuthenticationManager) - .and() - .build(); + .httpBasic((basic) -> basic + .authenticationManager(customAuthenticationManager)) + .build(); // @formatter:on WebFilterChainProxy springSecurityFilterChain = new WebFilterChainProxy(securityFilterChain); // @formatter:off @@ -486,7 +479,8 @@ public class ServerHttpSecurityTests { public void addsX509FilterWhenX509AuthenticationIsConfigured() { X509PrincipalExtractor mockExtractor = mock(X509PrincipalExtractor.class); ReactiveAuthenticationManager mockAuthenticationManager = mock(ReactiveAuthenticationManager.class); - this.http.x509().principalExtractor(mockExtractor).authenticationManager(mockAuthenticationManager).and(); + this.http + .x509((x509) -> x509.principalExtractor(mockExtractor).authenticationManager(mockAuthenticationManager)); SecurityWebFilterChain securityWebFilterChain = this.http.build(); WebFilter x509WebFilter = securityWebFilterChain.getWebFilters().filter(this::isX509Filter).blockFirst(); assertThat(x509WebFilter).isNotNull(); @@ -505,7 +499,7 @@ public class ServerHttpSecurityTests { @Test public void addsX509FilterWhenX509AuthenticationIsConfiguredWithDefaults() { - this.http.x509(); + this.http.x509(withDefaults()); SecurityWebFilterChain securityWebFilterChain = this.http.build(); WebFilter x509WebFilter = securityWebFilterChain.getWebFilters().filter(this::isX509Filter).blockFirst(); assertThat(x509WebFilter).isNotNull(); @@ -600,13 +594,9 @@ public class ServerHttpSecurityTests { ServerRequestCache requestCache = spy(new WebSessionServerRequestCache()); ReactiveClientRegistrationRepository clientRegistrationRepository = mock( ReactiveClientRegistrationRepository.class); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Login() - .clientRegistrationRepository(clientRegistrationRepository) - .and() - .authorizeExchange() - .anyExchange() - .authenticated() - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Login((login) -> login.clientRegistrationRepository(clientRegistrationRepository)) + .authorizeExchange((exchange) -> exchange.anyExchange().authenticated()) .requestCache((c) -> c.requestCache(requestCache)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); @@ -633,10 +623,9 @@ public class ServerHttpSecurityTests { OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request().build(); given(authorizationRequestRepository.removeAuthorizationRequest(any())) .willReturn(Mono.just(authorizationRequest)); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Login() - .clientRegistrationRepository(clientRegistrationRepository) - .authorizationRequestRepository(authorizationRequestRepository) - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Login((login) -> login.clientRegistrationRepository(clientRegistrationRepository) + .authorizationRequestRepository(authorizationRequestRepository)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); client.get().uri("/login/oauth2/code/registration-id").exchange(); @@ -650,9 +639,8 @@ public class ServerHttpSecurityTests { given(clientRegistrationRepository.findByRegistrationId(anyString())) .willReturn(Mono.just(TestClientRegistrations.clientRegistration().build())); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Login() - .clientRegistrationRepository(clientRegistrationRepository) - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Login((login) -> login.clientRegistrationRepository(clientRegistrationRepository)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); @@ -674,10 +662,9 @@ public class ServerHttpSecurityTests { .willReturn(Mono.just(TestClientRegistrations.clientRegistration().build())); given(authorizationRedirectStrategy.sendRedirect(any(), any())).willReturn(Mono.empty()); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Login() - .clientRegistrationRepository(clientRegistrationRepository) - .authorizationRedirectStrategy(authorizationRedirectStrategy) - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Login((login) -> login.clientRegistrationRepository(clientRegistrationRepository) + .authorizationRedirectStrategy(authorizationRedirectStrategy)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); @@ -698,9 +685,8 @@ public class ServerHttpSecurityTests { given(clientRegistrationRepository.findByRegistrationId(anyString())) .willReturn(Mono.just(TestClientRegistrations.clientRegistration().build())); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Client() - .clientRegistrationRepository(clientRegistrationRepository) - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Client((client) -> client.clientRegistrationRepository(clientRegistrationRepository)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); @@ -722,10 +708,9 @@ public class ServerHttpSecurityTests { .willReturn(Mono.just(TestClientRegistrations.clientRegistration().build())); given(authorizationRedirectStrategy.sendRedirect(any(), any())).willReturn(Mono.empty()); - SecurityWebFilterChain securityFilterChain = this.http.oauth2Client() - .clientRegistrationRepository(clientRegistrationRepository) - .authorizationRedirectStrategy(authorizationRedirectStrategy) - .and() + SecurityWebFilterChain securityFilterChain = this.http + .oauth2Client((client) -> client.clientRegistrationRepository(clientRegistrationRepository) + .authorizationRedirectStrategy(authorizationRedirectStrategy)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); From 461f00ed3849fe46f2bdbe3603502e510bff184c Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:09:26 -0600 Subject: [PATCH 404/504] Use ServerHttpSecurity Lambda DSL in Config Issue gh-13067 --- .../reactive/ServerHttpSecurityConfiguration.java | 6 ++++-- .../web/reactive/WebFluxSecurityConfiguration.java | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java index 90b8bb19df..3f56ebea50 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java @@ -43,6 +43,8 @@ import org.springframework.security.web.reactive.result.method.annotation.Curren import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; +import static org.springframework.security.config.Customizer.withDefaults; + /** * @author Rob Winch * @author Dan Zheng @@ -156,8 +158,8 @@ class ServerHttpSecurityConfiguration { ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity(); // @formatter:off return http.authenticationManager(authenticationManager()) - .headers().and() - .logout().and(); + .headers(withDefaults()) + .logout(withDefaults()); // @formatter:on } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java index 0ead8c280a..0afea13f5a 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java @@ -40,6 +40,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.reactive.result.view.AbstractView; +import static org.springframework.security.config.Customizer.withDefaults; + /** * @author Rob Winch * @since 5.0 @@ -121,13 +123,13 @@ class WebFluxSecurityConfiguration { * @return */ private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange().anyExchange().authenticated(); + http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); if (isOAuth2Present && OAuth2ClasspathGuard.shouldConfigure(this.context)) { OAuth2ClasspathGuard.configure(this.context, http); } else { - http.httpBasic(); - http.formLogin(); + http.httpBasic(withDefaults()); + http.formLogin(withDefaults()); } SecurityWebFilterChain result = http.build(); return result; @@ -136,8 +138,8 @@ class WebFluxSecurityConfiguration { private static class OAuth2ClasspathGuard { static void configure(ApplicationContext context, ServerHttpSecurity http) { - http.oauth2Login(); - http.oauth2Client(); + http.oauth2Login(withDefaults()); + http.oauth2Client(withDefaults()); } static boolean shouldConfigure(ApplicationContext context) { From f789abc87fab546ee8cea03967cf521c18251512 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:10:02 -0600 Subject: [PATCH 405/504] Use ServerHttpSecurity Lambda DSL in JavaDoc Issue gh-13067 --- .../config/web/server/ServerHttpSecurity.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index f0760bc64e..bd0b178804 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -270,10 +270,8 @@ import org.springframework.web.util.pattern.PathPatternParser; * @Bean * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { * http - * .authorizeExchange() - * .anyExchange().authenticated() - * .and() - * .httpBasic().and() + * .authorizeExchange((exchange) -> exchange.anyExchange().authenticated()) + * .httpBasic(Customizer.withDefaults()) * .formLogin(); * return http.build(); * } @@ -1219,9 +1217,8 @@ public class ServerHttpSecurity { * // ... * .headers() * // customize frame options to be same origin - * .frameOptions() - * .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN) - * .and() + * .frameOptions((frame) -> frame + * .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN)) * // disable cache control * .cache().disable(); * return http.build(); @@ -1857,7 +1854,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #authorizeExchange() + * @see #authorizeExchange(Customizer) */ public class AuthorizeExchangeSpec extends AbstractServerWebExchangeMatcherRegistry { @@ -2306,7 +2303,7 @@ public class ServerHttpSecurity { * * @author Josh Cummings * @since 5.1 - * @see #redirectToHttps() + * @see #redirectToHttps(Customizer) */ public class HttpsRedirectSpec { @@ -2380,7 +2377,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #csrf() + * @see #csrf(Customizer) */ public final class CsrfSpec { @@ -2483,7 +2480,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #exceptionHandling() + * @see #exceptionHandling(Customizer) */ public final class ExceptionHandlingSpec { @@ -2532,7 +2529,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #requestCache() + * @see #requestCache(Customizer) */ public final class RequestCacheSpec { @@ -2588,7 +2585,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #httpBasic() + * @see #httpBasic(Customizer) */ public final class HttpBasicSpec { @@ -2814,7 +2811,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #formLogin() + * @see #formLogin(Customizer) */ public final class FormLoginSpec { @@ -3080,7 +3077,7 @@ public class ServerHttpSecurity { * * @author Rob Winch * @since 5.0 - * @see #headers() + * @see #headers(Customizer) */ public final class HeaderSpec { @@ -3916,7 +3913,7 @@ public class ServerHttpSecurity { * * @author Shazin Sadakath * @since 5.0 - * @see #logout() + * @see #logout(Customizer) */ public final class LogoutSpec { @@ -4136,7 +4133,7 @@ public class ServerHttpSecurity { * * @author Alexey Nesterov * @since 5.2 - * @see #x509() + * @see #x509(Customizer) */ public final class X509Spec { @@ -5275,7 +5272,7 @@ public class ServerHttpSecurity { AndServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher( CsrfWebFilter.DEFAULT_CSRF_MATCHER, new NegatedServerWebExchangeMatcher(this.authenticationConverterServerWebExchangeMatcher)); - http.csrf().requireCsrfProtectionMatcher(matcher); + http.csrf((csrf) -> csrf.requireCsrfProtectionMatcher(matcher)); } } From 5dd40a7f100b2aff6c8c11f594e6aff2c5f2e1a8 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:39:09 -0600 Subject: [PATCH 406/504] Remove ServerHttpSecurity and() DSL Methods This commit removes all and() DSL methods with the exception of featurePolicy, which will be removed as a whole at another time. Closes gh-13067 --- .../config/web/server/ServerHttpSecurity.java | 1058 +---------------- 1 file changed, 3 insertions(+), 1055 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index bd0b178804..3e93825f79 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -436,48 +436,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures HTTPS redirection rules. If the default is used: - * - *
-	 *  @Bean
-	 * 	public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 * 	    http
-	 * 	        // ...
-	 * 	        .redirectToHttps();
-	 * 	    return http.build();
-	 * 	}
-	 * 
- * - * Then all non-HTTPS requests will be redirected to HTTPS. - * - * Typically, all requests should be HTTPS; however, the focus for redirection can - * also be narrowed: - * - *
-	 *  @Bean
-	 * 	public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 * 	    http
-	 * 	        // ...
-	 * 	        .redirectToHttps()
-	 * 	            .httpsRedirectWhen((serverWebExchange) ->
-	 * 	            	serverWebExchange.getRequest().getHeaders().containsKey("X-Requires-Https"))
-	 * 	    return http.build();
-	 * 	}
-	 * 
- * @return the {@link HttpsRedirectSpec} to customize - * @deprecated For removal in 7.0. Use {@link #redirectToHttps(Customizer)} or - * {@code redirectToHttps(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HttpsRedirectSpec redirectToHttps() { - this.httpsRedirectSpec = new HttpsRedirectSpec(); - return this.httpsRedirectSpec; - } - /** * Configures HTTPS redirection rules. If the default is used: * @@ -519,53 +477,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures CSRF - * Protection which is enabled by default. You can disable it using: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .csrf().disabled();
-	 *      return http.build();
-	 *  }
-	 * 
- * - * Additional configuration options can be seen below: - * - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .csrf()
-	 *              // Handle CSRF failures
-	 *              .accessDeniedHandler(accessDeniedHandler)
-	 *              // Custom persistence of CSRF Token
-	 *              .csrfTokenRepository(csrfTokenRepository)
-	 *              // custom matching when CSRF protection is enabled
-	 *              .requireCsrfProtectionMatcher(matcher);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link CsrfSpec} to customize - * @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or - * {@code csrf(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CsrfSpec csrf() { - if (this.csrf == null) { - this.csrf = new CsrfSpec(); - } - return this.csrf; - } - /** * Configures CSRF @@ -615,26 +526,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures CORS headers. By default if a {@link CorsConfigurationSource} Bean is - * found, it will be used to create a {@link CorsWebFilter}. If - * {@link CorsSpec#configurationSource(CorsConfigurationSource)} is invoked it will be - * used instead. If neither has been configured, the Cors configuration will do - * nothing. - * @return the {@link CorsSpec} to customize - * @deprecated For removal in 7.0. Use {@link #cors(Customizer)} or - * {@code cors(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CorsSpec cors() { - if (this.cors == null) { - this.cors = new CorsSpec(); - } - return this.cors; - } - /** * Configures CORS headers. By default if a {@link CorsConfigurationSource} Bean is * found, it will be used to create a {@link CorsWebFilter}. If @@ -653,36 +544,6 @@ public class ServerHttpSecurity { return this; } - /** - * Enables and Configures anonymous authentication. Anonymous Authentication is - * disabled by default. - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .anonymous().key("key")
-	 *          .authorities("ROLE_ANONYMOUS");
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link AnonymousSpec} to customize - * @since 5.2.0 - * @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or - * {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public AnonymousSpec anonymous() { - if (this.anonymous == null) { - this.anonymous = new AnonymousSpec(); - } - return this.anonymous; - } - /** * Enables and Configures anonymous authentication. Anonymous Authentication is * disabled by default. @@ -712,37 +573,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures HTTP Basic authentication. An example configuration is provided below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .httpBasic()
-	 *              // used for authenticating the credentials
-	 *              .authenticationManager(authenticationManager)
-	 *              // Custom persistence of the authentication
-	 *              .securityContextRepository(securityContextRepository);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link HttpBasicSpec} to customize - * @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or - * {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HttpBasicSpec httpBasic() { - if (this.httpBasic == null) { - this.httpBasic = new HttpBasicSpec(); - } - return this.httpBasic; - } - /** * Configures HTTP Basic authentication. An example configuration is provided below: * @@ -803,34 +633,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures password management. An example configuration is provided below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .passwordManagement();
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link PasswordManagementSpec} to customize - * @since 5.6 - * @deprecated For removal in 7.0. Use {@link #passwordManagement(Customizer)} or - * {@code passwordManagement(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public PasswordManagementSpec passwordManagement() { - if (this.passwordManagement == null) { - this.passwordManagement = new PasswordManagementSpec(); - } - return this.passwordManagement; - } - /** * Configures password management. An example configuration is provided below: * @@ -859,41 +661,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures form based authentication. An example configuration is provided below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .formLogin()
-	 *              // used for authenticating the credentials
-	 *              .authenticationManager(authenticationManager)
-	 *              // Custom persistence of the authentication
-	 *              .securityContextRepository(securityContextRepository)
-	 *              // expect a log in page at "/authenticate"
-	 *              // a POST "/authenticate" is where authentication occurs
-	 *              // error page at "/authenticate?error"
-	 *              .loginPage("/authenticate");
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link FormLoginSpec} to customize - * @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or - * {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public FormLoginSpec formLogin() { - if (this.formLogin == null) { - this.formLogin = new FormLoginSpec(); - } - return this.formLogin; - } - /** * Configures form based authentication. An example configuration is provided below: * @@ -928,39 +695,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures x509 authentication using a certificate provided by a client. - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          .x509()
-	 *          	.authenticationManager(authenticationManager)
-	 *              .principalExtractor(principalExtractor);
-	 *      return http.build();
-	 *  }
-	 * 
- * - * Note that if extractor is not specified, {@link SubjectX500PrincipalExtractor} will - * be used. If authenticationManager is not specified, - * {@link ReactivePreAuthenticatedAuthenticationManager} will be used. - * @return the {@link X509Spec} to customize - * @since 5.2 - * @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or - * {@code x509(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public X509Spec x509() { - if (this.x509 == null) { - this.x509 = new X509Spec(); - } - - return this.x509; - } - /** * Configures x509 authentication using a certificate provided by a client. * @@ -993,36 +727,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 - * Provider. - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .oauth2Login()
-	 *              .authenticationConverter(authenticationConverter)
-	 *              .authenticationManager(manager);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link OAuth2LoginSpec} to customize - * @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or - * {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2LoginSpec oauth2Login() { - if (this.oauth2Login == null) { - this.oauth2Login = new OAuth2LoginSpec(); - } - return this.oauth2Login; - } - /** * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 * Provider. @@ -1052,35 +756,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the OAuth2 client. - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .oauth2Client()
-	 *              .clientRegistrationRepository(clientRegistrationRepository)
-	 *              .authorizedClientRepository(authorizedClientRepository);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link OAuth2ClientSpec} to customize - * @deprecated For removal in 7.0. Use {@link #oauth2Client(Customizer)} or - * {@code oauth2Client(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ClientSpec oauth2Client() { - if (this.client == null) { - this.client = new OAuth2ClientSpec(); - } - return this.client; - } - /** * Configures the OAuth2 client. * @@ -1109,32 +784,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures OAuth 2.0 Resource Server support. - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .oauth2ResourceServer()
-	 *              .jwt()
-	 *                  .publicKey(publicKey());
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link OAuth2ResourceServerSpec} to customize - * @deprecated For removal in 7.0. Use {@link #oauth2ResourceServer(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ResourceServerSpec oauth2ResourceServer() { - if (this.resourceServer == null) { - this.resourceServer = new OAuth2ResourceServerSpec(); - } - return this.resourceServer; - } - /** * Configures OAuth 2.0 Resource Server support. * @@ -1193,51 +842,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures HTTP Response Headers. The default headers are: - * - *
-	 * Cache-Control: no-cache, no-store, max-age=0, must-revalidate
-	 * Pragma: no-cache
-	 * Expires: 0
-	 * X-Content-Type-Options: nosniff
-	 * Strict-Transport-Security: max-age=31536000 ; includeSubDomains
-	 * X-Frame-Options: DENY
-	 * X-XSS-Protection: 0
-	 * 
- * - * such that "Strict-Transport-Security" is only added on secure requests. - * - * An example configuration is provided below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .headers()
-	 *              // customize frame options to be same origin
-	 *              .frameOptions((frame) -> frame
-	 *                  .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN))
-	 *              // disable cache control
-	 *              .cache().disable();
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link HeaderSpec} to customize - * @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or - * {@code headers(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec headers() { - if (this.headers == null) { - this.headers = new HeaderSpec(); - } - return this.headers; - } - /** * Configures HTTP Response Headers. The default headers are: * @@ -1288,36 +892,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures exception handling (i.e. handles when authentication is requested). An - * example configuration can be found below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .exceptionHandling()
-	 *              // customize how to request for authentication
-	 *              .authenticationEntryPoint(entryPoint);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link ExceptionHandlingSpec} to customize - * @deprecated For removal in 7.0. Use {@link #exceptionHandling(Customizer)} or - * {@code exceptionHandling(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ExceptionHandlingSpec exceptionHandling() { - if (this.exceptionHandling == null) { - this.exceptionHandling = new ExceptionHandlingSpec(); - } - return this.exceptionHandling; - } - /** * Configures exception handling (i.e. handles when authentication is requested). An * example configuration can be found below: @@ -1347,49 +921,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures authorization. An example configuration can be found below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .authorizeExchange()
-	 *              // any URL that starts with /admin/ requires the role "ROLE_ADMIN"
-	 *              .pathMatchers("/admin/**").hasRole("ADMIN")
-	 *              // a POST to /users requires the role "USER_POST"
-	 *              .pathMatchers(HttpMethod.POST, "/users").hasAuthority("USER_POST")
-	 *              // a request to /users/{username} requires the current authentication's username
-	 *              // to be equal to the {username}
-	 *              .pathMatchers("/users/{username}").access((authentication, context) ->
-	 *                  authentication
-	 *                      .map(Authentication::getName)
-	 *                      .map((username) -> username.equals(context.getVariables().get("username")))
-	 *                      .map(AuthorizationDecision::new)
-	 *              )
-	 *              // allows providing a custom matching strategy that requires the role "ROLE_CUSTOM"
-	 *              .matchers(customMatcher).hasRole("CUSTOM")
-	 *              // any other request requires the user to be authenticated
-	 *              .anyExchange().authenticated();
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link AuthorizeExchangeSpec} to customize - * @deprecated For removal in 7.0. Use {@link #authorizeExchange(Customizer)} or - * {@code authorizeExchange(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public AuthorizeExchangeSpec authorizeExchange() { - if (this.authorizeExchange == null) { - this.authorizeExchange = new AuthorizeExchangeSpec(); - } - return this.authorizeExchange; - } - /** * Configures authorization. An example configuration can be found below: * @@ -1432,38 +963,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures log out. An example configuration can be found below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .logout()
-	 *              // configures how log out is done
-	 *              .logoutHandler(logoutHandler)
-	 *              // log out will be performed on POST /signout
-	 *              .logoutUrl("/signout")
-	 *              // configure what is done on logout success
-	 *              .logoutSuccessHandler(successHandler);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link LogoutSpec} to customize - * @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or - * {@code logout(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public LogoutSpec logout() { - if (this.logout == null) { - this.logout = new LogoutSpec(); - } - return this.logout; - } - /** * Configures log out. An example configuration can be found below: * @@ -1496,34 +995,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the request cache which is used when a flow is interrupted (i.e. due to - * requesting credentials) so that the request can be replayed after authentication. - * An example configuration can be found below: - * - *
-	 *  @Bean
-	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-	 *      http
-	 *          // ...
-	 *          .requestCache()
-	 *              // configures how the request is cached
-	 *              .requestCache(requestCache);
-	 *      return http.build();
-	 *  }
-	 * 
- * @return the {@link RequestCacheSpec} to customize - * @deprecated For removal in 7.0. Use {@link #requestCache(Customizer)} or - * {@code requestCache(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public RequestCacheSpec requestCache() { - return this.requestCache; - } - /** * Configures the request cache which is used when a flow is interrupted (i.e. due to * requesting credentials) so that the request can be replayed after authentication. @@ -1880,17 +1351,6 @@ public class ServerHttpSecurity { postProcessor.ifUnique((p) -> this.postProcessor = p); } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #authorizeExchange(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables authorization. * @return the {@link Access} to continue configuring @@ -2358,16 +1818,6 @@ public class ServerHttpSecurity { http.addFilterAt(httpsRedirectWebFilter, SecurityWebFiltersOrder.HTTPS_REDIRECT); } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated use {@link #redirectToHttps(Customizer)} - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - } /** @@ -2438,20 +1888,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #csrf(Customizer)} or - * {@code csrf(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables CSRF Protection. Disabling CSRF Protection is only recommended when * the application is never used within a browser. @@ -2510,17 +1946,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #exceptionHandling(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - } /** @@ -2555,27 +1980,13 @@ public class ServerHttpSecurity { http.addFilterAt(filter, SecurityWebFiltersOrder.SERVER_REQUEST_CACHE); } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #requestCache(Customizer)} or - * {@code requestCache(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables the {@link RequestCacheSpec} * @return the {@link ServerHttpSecurity} to continue configuring */ public ServerHttpSecurity disable() { this.requestCache = NoOpServerRequestCache.getInstance(); - return and(); + return ServerHttpSecurity.this; } } @@ -2696,20 +2107,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #httpBasic(Customizer)} or - * {@code httpBasic(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables HTTP Basic authentication. * @return the {@link ServerHttpSecurity} to continue configuring @@ -2783,17 +2180,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity}. - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #passwordManagement(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - protected void configure(ServerHttpSecurity http) { ExchangeMatcherRedirectWebFilter changePasswordWebFilter = new ExchangeMatcherRedirectWebFilter( new PathPatternParserServerWebExchangeMatcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), @@ -2967,20 +2353,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #formLogin(Customizer)} or - * {@code formLogin(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables HTTP Basic authentication. * @return the {@link ServerHttpSecurity} to continue configuring @@ -3114,20 +2486,6 @@ public class ServerHttpSecurity { this.crossOriginResourcePolicy)); } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #headers(Customizer)} or - * {@code headers(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables http response headers * @return the {@link ServerHttpSecurity} to continue configuring @@ -3137,20 +2495,6 @@ public class ServerHttpSecurity { return ServerHttpSecurity.this; } - /** - * Configures cache control headers - * @return the {@link CacheSpec} to configure - * @deprecated For removal in 7.0. Use {@link #cache(Customizer)} or - * {@code cache(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public CacheSpec cache() { - return new CacheSpec(); - } - /** * Configures cache control headers * @param cacheCustomizer the {@link Customizer} to provide more options for the @@ -3162,17 +2506,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures content type response headers - * @return the {@link ContentTypeOptionsSpec} to configure - * @deprecated For removal in 7.0. Use {@link #contentTypeOptions(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ContentTypeOptionsSpec contentTypeOptions() { - return new ContentTypeOptionsSpec(); - } - /** * Configures content type response headers * @param contentTypeOptionsCustomizer the {@link Customizer} to provide more @@ -3184,20 +2517,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures frame options response headers - * @return the {@link FrameOptionsSpec} to configure - * @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} or - * {@code frameOptions(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public FrameOptionsSpec frameOptions() { - return new FrameOptionsSpec(); - } - /** * Configures frame options response headers * @param frameOptionsCustomizer the {@link Customizer} to provide more options @@ -3222,20 +2541,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the Strict Transport Security response headers - * @return the {@link HstsSpec} to configure - * @deprecated For removal in 7.0. Use {@link #hsts(Customizer)} or - * {@code hsts(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HstsSpec hsts() { - return new HstsSpec(); - } - /** * Configures the Strict Transport Security response headers * @param hstsCustomizer the {@link Customizer} to provide more options for the @@ -3253,20 +2558,6 @@ public class ServerHttpSecurity { http.addFilterAt(result, SecurityWebFiltersOrder.HTTP_HEADERS_WRITER); } - /** - * Configures x-xss-protection response header. - * @return the {@link XssProtectionSpec} to configure - * @deprecated For removal in 7.0. Use {@link #xssProtection(Customizer)} or - * {@code xssProtection(Customizer.withDefaults())} to stick with defaults. See - * the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public XssProtectionSpec xssProtection() { - return new XssProtectionSpec(); - } - /** * Configures x-xss-protection response header. * @param xssProtectionCustomizer the {@link Customizer} to provide more options @@ -3278,18 +2569,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures {@code Content-Security-Policy} response header. - * @param policyDirectives the policy directive(s) - * @return the {@link ContentSecurityPolicySpec} to configure - * @deprecated For removal in 7.0. Use {@link #contentSecurityPolicy(Customizer)} - * instead. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ContentSecurityPolicySpec contentSecurityPolicy(String policyDirectives) { - return new ContentSecurityPolicySpec(policyDirectives); - } - /** * Configures {@code Content-Security-Policy} response header. * @param contentSecurityPolicyCustomizer the {@link Customizer} to provide more @@ -3313,17 +2592,6 @@ public class ServerHttpSecurity { return new FeaturePolicySpec(policyDirectives); } - /** - * Configures {@code Permissions-Policy} response header. - * @return the {@link PermissionsPolicySpec} to configure - * @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)} - * instead. - */ - @Deprecated(since = "6.1", forRemoval = true) - public PermissionsPolicySpec permissionsPolicy() { - return new PermissionsPolicySpec(); - } - /** * Configures {@code Permissions-Policy} response header. * @param permissionsPolicyCustomizer the {@link Customizer} to provide more @@ -3335,29 +2603,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures {@code Referrer-Policy} response header. - * @param referrerPolicy the policy to use - * @return the {@link ReferrerPolicySpec} to configure - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} - * instead. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ReferrerPolicySpec referrerPolicy(ReferrerPolicy referrerPolicy) { - return new ReferrerPolicySpec(referrerPolicy); - } - - /** - * Configures {@code Referrer-Policy} response header. - * @return the {@link ReferrerPolicySpec} to configure - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} - * instead. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ReferrerPolicySpec referrerPolicy() { - return new ReferrerPolicySpec(); - } - /** * Configures {@code Referrer-Policy} response header. * @param referrerPolicyCustomizer the {@link Customizer} to provide more options @@ -3369,21 +2614,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the - * Cross-Origin-Opener-Policy header. - * @return the {@link CrossOriginOpenerPolicySpec} to configure - * @since 5.7 - * @deprecated For removal in 7.0. Use - * {@link #crossOriginOpenerPolicy(Customizer)} instead. - * @see CrossOriginOpenerPolicyServerHttpHeadersWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginOpenerPolicySpec crossOriginOpenerPolicy() { - return new CrossOriginOpenerPolicySpec(); - } - /** * Configures the @@ -3398,21 +2628,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the - * Cross-Origin-Embedder-Policy header. - * @return the {@link CrossOriginEmbedderPolicySpec} to configure - * @since 5.7 - * @deprecated For removal in 7.0. Use - * {@link #crossOriginEmbedderPolicy(Customizer)} instead. - * @see CrossOriginEmbedderPolicyServerHttpHeadersWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginEmbedderPolicySpec crossOriginEmbedderPolicy() { - return new CrossOriginEmbedderPolicySpec(); - } - /** * Configures the @@ -3427,21 +2642,6 @@ public class ServerHttpSecurity { return this; } - /** - * Configures the - * Cross-Origin-Resource-Policy header. - * @return the {@link CrossOriginResourcePolicySpec} to configure - * @since 5.7 - * @deprecated For removal in 7.0. Use - * {@link #crossOriginResourcePolicy(Customizer)} instead. - * @see CrossOriginResourcePolicyServerHttpHeadersWriter - */ - @Deprecated(since = "6.1", forRemoval = true) - public CrossOriginResourcePolicySpec crossOriginResourcePolicy() { - return new CrossOriginResourcePolicySpec(); - } - /** * Configures the @@ -3516,18 +2716,6 @@ public class ServerHttpSecurity { */ public HeaderSpec mode(XFrameOptionsServerHttpHeadersWriter.Mode mode) { HeaderSpec.this.frameOptions.setMode(mode); - return and(); - } - - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity} - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use {@link #frameOptions(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - private HeaderSpec and() { return HeaderSpec.this; } @@ -3537,7 +2725,7 @@ public class ServerHttpSecurity { */ public HeaderSpec disable() { HeaderSpec.this.writers.remove(HeaderSpec.this.frameOptions); - return and(); + return HeaderSpec.this; } } @@ -3590,21 +2778,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity} - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use {@link #hsts(Customizer)} or - * {@code hsts(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - /** * Disables strict transport security response header * @return the {@link HeaderSpec} to continue configuring @@ -3685,18 +2858,6 @@ public class ServerHttpSecurity { return HeaderSpec.this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use - * {@link #contentSecurityPolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - private ContentSecurityPolicySpec(String policyDirectives) { HeaderSpec.this.contentSecurityPolicy.setPolicyDirectives(policyDirectives); } @@ -3750,18 +2911,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use {@link #permissionsPolicy(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - } /** @@ -3790,18 +2939,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use {@link #referrerPolicy(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - } /** @@ -3824,18 +2961,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use - * {@link #crossOriginOpenerPolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - } /** @@ -3858,18 +2983,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use - * {@link #crossOriginEmbedderPolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - } /** @@ -3892,18 +3005,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity}. - * @return the {@link HeaderSpec} to continue configuring - * @deprecated For removal in 7.0. Use - * {@link #crossOriginResourcePolicy(Customizer)} instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HeaderSpec and() { - return HeaderSpec.this; - } - } } @@ -3972,27 +3073,13 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #logout(Customizer)} or - * {@code logout(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables log out * @return the {@link ServerHttpSecurity} to continue configuring */ public ServerHttpSecurity disable() { ServerHttpSecurity.this.logout = null; - return and(); + return ServerHttpSecurity.this; } private ServerLogoutHandler createLogoutHandler() { @@ -4089,20 +3176,6 @@ public class ServerHttpSecurity { return ServerHttpSecurity.this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #cors(Customizer)} or - * {@code cors(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - protected void configure(ServerHttpSecurity http) { CorsWebFilter corsFilter = getCorsFilter(); if (corsFilter != null) { @@ -4154,18 +3227,6 @@ public class ServerHttpSecurity { return this; } - /** - * @deprecated For removal in 7.0. Use {@link #x509(Customizer)} or - * {@code x509(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - protected void configure(ServerHttpSecurity http) { ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); X509PrincipalExtractor principalExtractor = getPrincipalExtractor(); @@ -4466,20 +3527,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #oauth2Login(Customizer)} or - * {@code oauth2Login(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - protected void configure(ServerHttpSecurity http) { ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); @@ -4998,20 +4045,6 @@ public class ServerHttpSecurity { return this.authorizationRedirectStrategy; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #oauth2Client(Customizer)} or - * {@code oauth2Client(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - protected void configure(ServerHttpSecurity http) { ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); ServerAuthenticationConverter authenticationConverter = getAuthenticationConverter(); @@ -5152,22 +4185,6 @@ public class ServerHttpSecurity { return this; } - /** - * Enables JWT Resource Server support. - * @return the {@link JwtSpec} for additional configuration - * @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or - * {@code jwt(Customizer.withDefaults())} to stick with defaults. See the documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public JwtSpec jwt() { - if (this.jwt == null) { - this.jwt = new JwtSpec(); - } - return this.jwt; - } - /** * Enables JWT Resource Server support. * @param jwtCustomizer the {@link Customizer} to provide more options for the @@ -5182,23 +4199,6 @@ public class ServerHttpSecurity { return this; } - /** - * Enables Opaque Token Resource Server support. - * @return the {@link OpaqueTokenSpec} for additional configuration - * @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} or - * {@code opaqueToken(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OpaqueTokenSpec opaqueToken() { - if (this.opaqueToken == null) { - this.opaqueToken = new OpaqueTokenSpec(); - } - return this.opaqueToken; - } - /** * Enables Opaque Token Resource Server support. * @param opaqueTokenCustomizer the {@link Customizer} to provide more options for @@ -5283,15 +4283,6 @@ public class ServerHttpSecurity { return new ServerAuthenticationEntryPointFailureHandler(this.entryPoint); } - /** - * @deprecated For removal in 7.0. Use {@link #oauth2ResourceServer(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Configures JWT Resource Server Support */ @@ -5361,18 +4352,6 @@ public class ServerHttpSecurity { return this; } - /** - * @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or - * {@code jwt(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ResourceServerSpec and() { - return OAuth2ResourceServerSpec.this; - } - protected void configure(ServerHttpSecurity http) { ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager); @@ -5481,18 +4460,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the - * {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #opaqueToken(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public OAuth2ResourceServerSpec and() { - return OAuth2ResourceServerSpec.this; - } - protected ReactiveAuthenticationManager getAuthenticationManager() { OpaqueTokenReactiveAuthenticationManager authenticationManager = new OpaqueTokenReactiveAuthenticationManager( getIntrospector()); @@ -5581,11 +4548,6 @@ public class ServerHttpSecurity { return this; } - @Deprecated(forRemoval = true, since = "6.2") - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - void configure(ServerHttpSecurity http) { if (this.backChannel != null) { this.backChannel.configure(http); @@ -5884,20 +4846,6 @@ public class ServerHttpSecurity { return this; } - /** - * Allows method chaining to continue configuring the {@link ServerHttpSecurity} - * @return the {@link ServerHttpSecurity} to continue configuring - * @deprecated For removal in 7.0. Use {@link #anonymous(Customizer)} or - * {@code anonymous(Customizer.withDefaults())} to stick with defaults. See the - * documentation - * for more details. - */ - @Deprecated(since = "6.1", forRemoval = true) - public ServerHttpSecurity and() { - return ServerHttpSecurity.this; - } - /** * Disables anonymous authentication. * @return the {@link ServerHttpSecurity} to continue configuring From cf6b52d6f75bf957cda6adf10201ce9e4acb69ce Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:55:21 -0600 Subject: [PATCH 407/504] Format authorizeRequests Blocks This commit changes all auhorizeRequests declarations to use the same variable name and declare the lambda parameter and reference on the same line. Issue gh-13067 --- .../configurers/AnonymousConfigurerTests.java | 6 ++--- .../configurers/AuthorizeRequestsTests.java | 12 ++++------ .../web/configurers/CorsConfigurerTests.java | 9 +++----- ...ingConfigurerAccessDeniedHandlerTests.java | 3 +-- .../configurers/FormLoginConfigurerTests.java | 9 +++----- .../configurers/HttpBasicConfigurerTests.java | 3 +-- .../HttpSecurityRequestMatchersTests.java | 6 ++--- .../web/configurers/JeeConfigurerTests.java | 9 +++----- .../configurers/NamespaceHttpBasicTests.java | 9 +++----- ...aceHttpServerAccessDeniedHandlerTests.java | 6 ++--- .../RememberMeConfigurerTests.java | 9 +++----- .../RequestCacheConfigurerTests.java | 9 +++----- .../RequestMatcherConfigurerTests.java | 3 +-- .../client/OAuth2ClientConfigurerTests.java | 3 +-- .../OAuth2ResourceServerConfigurerTests.java | 22 +++++++------------ 15 files changed, 40 insertions(+), 78 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java index 49b5d7d962..7a6d0a94bd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java @@ -147,8 +147,7 @@ public class AnonymousConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().permitAll() ) .anonymous(AbstractHttpConfigurer::disable); @@ -171,8 +170,7 @@ public class AnonymousConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().permitAll() ) .anonymous(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java index 0b79c086a7..992dc0de1f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java @@ -219,8 +219,7 @@ public class AuthorizeRequestsTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers(new AntPathRequestMatcher("/**", HttpMethod.POST.name())).denyAll() ); // @formatter:on @@ -349,8 +348,7 @@ public class AuthorizeRequestsTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers("/path").denyAll() ); // @formatter:on @@ -421,8 +419,7 @@ public class AuthorizeRequestsTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers(mvcMatcherBuilder.pattern("/path")).denyAll() ); // @formatter:on @@ -489,8 +486,7 @@ public class AuthorizeRequestsTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers("/user/{userName}").access("#userName == 'user'") ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java index a7935fdde5..bcb7e2e82b 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java @@ -251,8 +251,7 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .cors(withDefaults()); @@ -308,8 +307,7 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .cors(withDefaults()); @@ -364,8 +362,7 @@ public class CorsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .cors(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java index 5b92a1af89..b4f9ec3a08 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java @@ -113,8 +113,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) .exceptionHandling((exceptionHandling) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java index 8401ef354e..2adfb030b0 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java @@ -453,8 +453,7 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .formLogin(withDefaults()); @@ -516,8 +515,7 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .formLogin((formLogin) -> @@ -572,8 +570,7 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin((formLogin) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java index ce019a7f1d..c898e973c7 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java @@ -250,8 +250,7 @@ public class HttpBasicConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .httpBasic(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java index 73a03f4cad..747dabafe5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java @@ -341,8 +341,7 @@ public class HttpSecurityRequestMatchersTests { .requestMatchers(new MvcRequestMatcher(introspector, "/path")) ) .httpBasic(withDefaults()) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ); return http.build(); @@ -416,8 +415,7 @@ public class HttpSecurityRequestMatchersTests { .requestMatchers("/never-match") ) .httpBasic(withDefaults()) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java index 527933f178..930b55b6c5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java @@ -209,8 +209,7 @@ public class JeeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .jee((jee) -> @@ -231,8 +230,7 @@ public class JeeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .jee((jee) -> @@ -256,8 +254,7 @@ public class JeeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .jee((jee) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java index c1fa89078a..2f83d45a13 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java @@ -200,8 +200,7 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .httpBasic(withDefaults()); @@ -236,8 +235,7 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .httpBasic((httpBasicConfig) -> httpBasicConfig.realmName("Custom Realm")); @@ -325,8 +323,7 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .httpBasic((httpBasicConfig) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java index 8980c95c8c..67eba03574 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java @@ -130,8 +130,7 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) .exceptionHandling((exceptionHandling) -> @@ -176,8 +175,7 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) .exceptionHandling((exceptionHandling) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java index 73be687d53..2859889e26 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java @@ -508,8 +508,7 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .formLogin(withDefaults()) @@ -557,8 +556,7 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .formLogin(withDefaults()) @@ -636,8 +634,7 @@ public class RememberMeConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .sessionManagement((sessionManagement) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java index f22d69e1a3..3c30f762a4 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java @@ -412,8 +412,7 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) @@ -432,8 +431,7 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) @@ -452,8 +450,7 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java index f8b18381be..c6a6f366b4 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java @@ -106,8 +106,7 @@ public class RequestMatcherConfigurerTests { matchers .requestMatchers(new AntPathRequestMatcher("/oauth/**")) ) - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java index 15f011de74..e33f1f9760 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java @@ -399,8 +399,7 @@ public class OAuth2ClientConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2Client(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index c7c31aa5e4..db701a0080 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1395,10 +1395,9 @@ public class OAuth2ResourceServerConfigurerTests { context.registerBean("converterOne", JwtAuthenticationConverter.class, () -> converterBean); context.registerBean("converterTwo", JwtAuthenticationConverter.class, () -> converterBean); this.spring.context(context).autowire(); - new OAuth2ResourceServerConfigurer(context).jwt((jwt) -> { - assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) - .isThrownBy(jwt::getJwtAuthenticationConverter); - }); + new OAuth2ResourceServerConfigurer(context) + .jwt((jwt) -> assertThatExceptionOfType(NoUniqueBeanDefinitionException.class) + .isThrownBy(jwt::getJwtAuthenticationConverter)); } @Test @@ -1577,8 +1576,7 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") .anyRequest().authenticated() ) @@ -1630,8 +1628,7 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") .anyRequest().authenticated() ) @@ -2122,8 +2119,7 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2ResourceServer((oauth2ResourceServer) -> @@ -2386,8 +2382,7 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .requestMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read") .anyRequest().authenticated() ) @@ -2433,8 +2428,7 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeRequests((authorizeRequests) -> - authorizeRequests + .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2ResourceServer((oauth2ResourceServer) -> From 777447e1d96aa717a91dd17023adf889ef1c8042 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:06:52 -0600 Subject: [PATCH 408/504] Format authorizeHttpRequests Blocks This commit formats authorizeHttpRequests blocks to use the same parameter name and places the reference on the same line as the parameter. Issue gh-13067 --- .../annotation/web/builders/HttpSecurity.java | 12 ++--- .../DeferHttpSessionJavaConfigTests.java | 2 +- .../HttpSecurityConfigurationTests.java | 6 +-- .../WebSecurityConfigurationTests.java | 6 +-- .../AuthorizeHttpRequestsConfigurerTests.java | 48 +++++++++---------- .../configurers/FormLoginConfigurerTests.java | 2 +- .../HttpSecurityObservationTests.java | 2 +- ...ttpSecuritySecurityMatchersNoMvcTests.java | 2 +- .../HttpSecuritySecurityMatchersTests.java | 10 ++-- .../configurers/NamespaceRememberMeTests.java | 2 +- .../configurers/PermitAllSupportTests.java | 4 +- .../RequestCacheConfigurerTests.java | 2 +- .../ServletApiConfigurerTests.java | 2 +- .../client/OAuth2LoginConfigurerTests.java | 3 +- .../DPoPAuthenticationConfigurerTests.java | 3 +- .../ott/OneTimeTokenLoginConfigurerTests.java | 10 ++-- .../saml2/Saml2LoginConfigurerTests.java | 4 +- .../servlet/saml2/login/authentication.adoc | 8 ++-- .../showcase/login/AuthenticationTests.java | 2 +- 19 files changed, 62 insertions(+), 68 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 4a4c3cc42e..1c89141824 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -125,8 +125,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector; * @Bean * public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { * http - * .authorizeHttpRequests((authorizeHttpRequests) -> - * authorizeHttpRequests + * .authorizeHttpRequests((authorize) -> authorize * .requestMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()); @@ -785,8 +784,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().permitAll() ) .sessionManagement((sessions) -> sessions diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java index 4809552722..5f45eeefe5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java @@ -524,7 +524,7 @@ public class HttpSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .authorizeRequests((requests) -> requests @@ -547,7 +547,7 @@ public class HttpSecurityConfigurationTests { .authorizeRequests((requests) -> requests .anyRequest().authenticated() ) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .build(); @@ -634,7 +634,7 @@ public class HttpSecurityConfigurationTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java index afabd761ba..311bae361d 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java @@ -912,7 +912,7 @@ public class WebSecurityConfigurationTests { // @formatter:off http .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/user"))) - .authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("USER")); + .authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("USER")); // @formatter:on return http.build(); } @@ -923,7 +923,7 @@ public class WebSecurityConfigurationTests { // @formatter:off http .securityMatchers((requests) -> requests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher("/admin"))) - .authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ADMIN")); + .authorizeHttpRequests((authorize) -> authorize.anyRequest().hasRole("ADMIN")); // @formatter:on return http.build(); } @@ -931,7 +931,7 @@ public class WebSecurityConfigurationTests { @Bean @Order(Ordered.LOWEST_PRECEDENCE) public SecurityFilterChain permitAll(HttpSecurity http) throws Exception { - http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); + http.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll()); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index ea79dda610..b2bd973bee 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -793,7 +793,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest()); // @formatter:on @@ -810,7 +810,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() .requestMatchers("/path").hasRole("USER") ) @@ -830,7 +830,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().access(authorizationManager) ) .build(); @@ -849,7 +849,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().access(authorizationManager)); // @formatter:on @@ -868,7 +868,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .build(); @@ -900,7 +900,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasAnyAuthority("ROLE_USER") ) .build(); @@ -918,7 +918,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasAuthority("ROLE_USER") ) .build(); @@ -936,7 +936,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN") ) .build(); @@ -953,7 +953,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .build(); @@ -970,7 +970,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) .build(); @@ -994,7 +994,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().hasAnyRole("USER", "ADMIN") ) .build(); @@ -1012,7 +1012,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll() ) .build(); @@ -1029,7 +1029,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().permitAll() ) .build(); @@ -1047,7 +1047,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .authorizeHttpRequests(withDefaults()) @@ -1068,7 +1068,7 @@ public class AuthorizeHttpRequestsConfigurerTests { .servletPath("/spring"); // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .requestMatchers(mvcMatcherBuilder.pattern("/")).hasRole("ADMIN") ) .build(); @@ -1086,7 +1086,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off return http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .build(); @@ -1109,7 +1109,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().access(new WebExpressionAuthorizationManager("hasRole('USER')")) ) .build(); @@ -1126,7 +1126,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().access(new WebExpressionAuthorizationManager("hasRole('USER') or hasRole('ADMIN')")) ) .build(); @@ -1143,7 +1143,7 @@ public class AuthorizeHttpRequestsConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off return http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().access(new WebExpressionAuthorizationManager("hasIpAddress('127.0.0.1')")) ) .build(); @@ -1162,7 +1162,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/user/{username}").access(new WebExpressionAuthorizationManager("#username == 'user'")) .requestMatchers("/v2/user/{username}").hasVariable("username").equalTo(Authentication::getName) ); @@ -1197,7 +1197,7 @@ public class AuthorizeHttpRequestsConfigurerTests { http .httpBasic(withDefaults()) .rememberMe(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().fullyAuthenticated() ); // @formatter:on @@ -1221,7 +1221,7 @@ public class AuthorizeHttpRequestsConfigurerTests { http .httpBasic(withDefaults()) .rememberMe(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().rememberMe() ); // @formatter:on @@ -1244,7 +1244,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().anonymous() ); // @formatter:on @@ -1262,7 +1262,7 @@ public class AuthorizeHttpRequestsConfigurerTests { // @formatter:off http .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().not().authenticated() ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java index 2adfb030b0..1c13a37377 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java @@ -724,7 +724,7 @@ public class FormLoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityObservationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityObservationTests.java index 2bb4e9684d..562b206718 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityObservationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityObservationTests.java @@ -87,7 +87,7 @@ public class HttpSecurityObservationTests { @Bean SecurityFilterChain app(HttpSecurity http) throws Exception { - http.httpBasic(withDefaults()).authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()); + http.httpBasic(withDefaults()).authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java index 7dca1b7b5e..c6afdf3572 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersNoMvcTests.java @@ -123,7 +123,7 @@ public class HttpSecuritySecurityMatchersNoMvcTests { http .securityMatcher("/path") .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll()); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java index b476c45c38..9de85b6957 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecuritySecurityMatchersTests.java @@ -226,7 +226,7 @@ public class HttpSecuritySecurityMatchersTests { .requestMatchers("/test-1") .requestMatchers("/test-2") .requestMatchers("/test-3")) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll()) .httpBasic(withDefaults()); // @formatter:on @@ -239,7 +239,7 @@ public class HttpSecuritySecurityMatchersTests { http .securityMatchers((security) -> security .requestMatchers("/test-1")) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().permitAll()); // @formatter:on return http.build(); @@ -269,7 +269,7 @@ public class HttpSecuritySecurityMatchersTests { http .securityMatcher("/path") .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll()); // @formatter:on return http.build(); @@ -299,7 +299,7 @@ public class HttpSecuritySecurityMatchersTests { http .securityMatcher("/path") .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll()); // @formatter:on return http.build(); @@ -366,7 +366,7 @@ public class HttpSecuritySecurityMatchersTests { .requestMatchers(mvcMatcherBuilder.pattern("/never-match")) ) .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().denyAll()); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java index a9434bef89..0d02e44132 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java @@ -350,7 +350,7 @@ public class NamespaceRememberMeTests { // @formatter:off http .securityMatcher(new AntPathRequestMatcher("/without-key/**")) - .authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()) + .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()) .formLogin((login) -> login .loginProcessingUrl("/without-key/login")) .rememberMe(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java index 1ff5905ca1..beffdbf486 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java @@ -119,7 +119,7 @@ public class PermitAllSupportTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated()) .formLogin((login) -> login .loginPage("/xyz").permitAll() @@ -140,7 +140,7 @@ public class PermitAllSupportTests { http .authorizeRequests((requests) -> requests .anyRequest().authenticated()) - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated()) .formLogin((login) -> login .loginPage("/xyz").permitAll() diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java index 3c30f762a4..bd1fcdfd20 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java @@ -393,7 +393,7 @@ public class RequestCacheConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java index f1df48be8c..e8465e2a5c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java @@ -253,7 +253,7 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 980c7c5995..6cfbccb1ea 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -1340,8 +1340,7 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((authorizeRequests) -> - authorizeRequests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .securityContext((securityContext) -> diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index 6ffab052e9..5dbdfa89de 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -240,8 +240,7 @@ public class DPoPAuthenticationConfigurerTests { SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((authorize) -> - authorize + .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/resource1").hasAnyAuthority("SCOPE_resource1.read", "SCOPE_resource1.write") .requestMatchers("/resource2").hasAnyAuthority("SCOPE_resource2.read", "SCOPE_resource2.write") .anyRequest().authenticated() diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurerTests.java index 0b965cfc2f..a93409ebdb 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurerTests.java @@ -242,7 +242,7 @@ public class OneTimeTokenLoginConfigurerTests { // @formatter:off http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oneTimeTokenLogin((ott) -> ott @@ -281,7 +281,7 @@ public class OneTimeTokenLoginConfigurerTests { OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception { // @formatter:off http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oneTimeTokenLogin((ott) -> ott @@ -308,7 +308,7 @@ public class OneTimeTokenLoginConfigurerTests { OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception { // @formatter:off http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oneTimeTokenLogin((ott) -> ott @@ -336,7 +336,7 @@ public class OneTimeTokenLoginConfigurerTests { OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception { // @formatter:off http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oneTimeTokenLogin((ott) -> ott @@ -365,7 +365,7 @@ public class OneTimeTokenLoginConfigurerTests { SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oneTimeTokenLogin(Customizer.withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java index 8db919dd72..f43ae69d86 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java @@ -630,7 +630,7 @@ public class Saml2LoginConfigurerTests { @Bean SecurityFilterChain app(HttpSecurity http) throws Exception { - http.authorizeHttpRequests((authz) -> authz.anyRequest().authenticated()) + http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()) .saml2Login(Customizer.withDefaults()); return http.build(); } @@ -715,7 +715,7 @@ public class Saml2LoginConfigurerTests { SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((authz) -> authz.anyRequest().authenticated()) + .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()) .saml2Login((saml2) -> saml2.authenticationRequestUriQuery("/custom/auth/sso?entityId={registrationId}")); // @formatter:on return http.build(); diff --git a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc index cf794fe100..bd9e738ad1 100644 --- a/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc +++ b/docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc @@ -148,7 +148,7 @@ public class SecurityConfig { ); http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .saml2Login((saml2) -> saml2 @@ -211,7 +211,7 @@ public class SecurityConfig { .clockSkew(Duration.ofMinutes(10)).build(); authenticationProvider.setAssertionValidator(assertionValidator); http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .saml2Login((saml2) -> saml2 @@ -274,7 +274,7 @@ public class SecurityConfig { authenticationProvider.setResponseAuthenticationConverter(this.authenticationConverter); http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated()) .saml2Login((saml2) -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) @@ -409,7 +409,7 @@ public class SecurityConfig { }); http - .authorizeHttpRequests((authz) -> authz + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .saml2Login((saml2) -> saml2 diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java index dfbff109e5..58e297b469 100644 --- a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java +++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java @@ -104,7 +104,7 @@ public class AuthenticationTests { DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception { // @formatter:off http - .authorizeHttpRequests((requests) -> requests + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .sessionManagement((sessions) -> sessions From da6c7b875916c67ccea209635da750cac1f14cce Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:16:20 -0600 Subject: [PATCH 409/504] Format Lambda Usage This commit updates Lambda DSL usage to favor having the variable and reference on the same line Issue gh-13067 --- .../rsocket/HelloRSocketITests.java | 3 +- .../HelloRSocketObservationITests.java | 3 +- .../HelloRSocketWithWebFluxITests.java | 3 +- .../config/annotation/rsocket/JwtITests.java | 3 +- ...RSocketMessageHandlerConnectionITests.java | 3 +- .../rsocket/RSocketMessageHandlerITests.java | 3 +- .../rsocket/SimpleAuthenticationITests.java | 3 +- .../configurers/AnonymousConfigurerTests.java | 3 +- .../ChannelSecurityConfigurerTests.java | 3 +- ...onfigurerIgnoringRequestMatchersTests.java | 6 +-- ...ingConfigurerAccessDeniedHandlerTests.java | 3 +- .../configurers/FormLoginConfigurerTests.java | 9 ++-- .../configurers/HeadersConfigurerTests.java | 51 +++++++------------ .../HttpSecurityRequestMatchersTests.java | 6 +-- .../web/configurers/JeeConfigurerTests.java | 9 ++-- .../configurers/LogoutConfigurerTests.java | 6 +-- .../configurers/NamespaceHttpBasicTests.java | 6 +-- .../configurers/NamespaceHttpLogoutTests.java | 3 +- ...aceHttpServerAccessDeniedHandlerTests.java | 6 +-- .../PortMapperConfigurerTests.java | 12 ++--- .../RememberMeConfigurerTests.java | 6 +-- .../RequestCacheConfigurerTests.java | 3 +- .../RequestMatcherConfigurerTests.java | 6 +-- .../SecurityContextConfigurerTests.java | 3 +- .../ServletApiConfigurerTests.java | 3 +- .../SessionManagementConfigurerTests.java | 15 ++---- .../web/configurers/X509ConfigurerTests.java | 3 +- .../client/OAuth2LoginConfigurerTests.java | 36 +++++-------- .../DPoPAuthenticationConfigurerTests.java | 3 +- .../OAuth2ResourceServerConfigurerTests.java | 24 +++------ .../config/web/server/HeaderSpecTests.java | 3 +- .../web/server/HttpsRedirectSpecTests.java | 6 +-- .../web/server/OAuth2ClientSpecTests.java | 3 +- .../config/web/server/OAuth2LoginTests.java | 6 +-- .../server/OAuth2ResourceServerSpecTests.java | 27 ++++------ 35 files changed, 97 insertions(+), 194 deletions(-) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketITests.java index b46c1e41ae..e8a279480d 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketITests.java @@ -74,8 +74,7 @@ public class HelloRSocketITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketObservationITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketObservationITests.java index 9b6cf17b8c..4c838e9278 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketObservationITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketObservationITests.java @@ -87,8 +87,7 @@ public class HelloRSocketObservationITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketWithWebFluxITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketWithWebFluxITests.java index 7b298b3c75..72ea1a6beb 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketWithWebFluxITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/HelloRSocketWithWebFluxITests.java @@ -74,8 +74,7 @@ public class HelloRSocketWithWebFluxITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java index 8af9308c29..39f35280b7 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/JwtITests.java @@ -86,8 +86,7 @@ public class JwtITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerConnectionITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerConnectionITests.java index 3e9da24ff8..540b82ba7f 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerConnectionITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerConnectionITests.java @@ -81,8 +81,7 @@ public class RSocketMessageHandlerConnectionITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerITests.java index ef65fb55c7..1ad42c1666 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/RSocketMessageHandlerITests.java @@ -79,8 +79,7 @@ public class RSocketMessageHandlerITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/SimpleAuthenticationITests.java b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/SimpleAuthenticationITests.java index 1e83469801..f6a63acf4b 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/SimpleAuthenticationITests.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/rsocket/SimpleAuthenticationITests.java @@ -79,8 +79,7 @@ public class SimpleAuthenticationITests { // @formatter:off this.server = RSocketServer.create() .payloadDecoder(PayloadDecoder.ZERO_COPY) - .interceptors((registry) -> - registry.forSocketAcceptor(this.interceptor) + .interceptors((registry) -> registry.forSocketAcceptor(this.interceptor) ) .acceptor(this.handler.responder()) .bind(TcpServerTransport.create("localhost", 0)) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java index 7a6d0a94bd..efa7735116 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java @@ -129,8 +129,7 @@ public class AnonymousConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .anonymous((anonymous) -> - anonymous + .anonymous((anonymous) -> anonymous .principal("principal") ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java index 21cbc87af8..7e18eb8d23 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java @@ -186,8 +186,7 @@ public class ChannelSecurityConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requiresChannel((requiresChannel) -> - requiresChannel + .requiresChannel((requiresChannel) -> requiresChannel .anyRequest().requiresSecure() ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java index bd22ccf67e..377445bb0a 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java @@ -128,8 +128,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf((csrf) -> - csrf + .csrf((csrf) -> csrf .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path")) .ignoringRequestMatchers(this.requestMatcher) ); @@ -169,8 +168,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .csrf((csrf) -> - csrf + .csrf((csrf) -> csrf .ignoringRequestMatchers(new AntPathRequestMatcher("/no-csrf")) .ignoringRequestMatchers(this.requestMatcher) ); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java index b4f9ec3a08..ad1de31fe2 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java @@ -116,8 +116,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests { .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) - .exceptionHandling((exceptionHandling) -> - exceptionHandling + .exceptionHandling((exceptionHandling) -> exceptionHandling .defaultAccessDeniedHandlerFor( this.teapotDeniedHandler, new AntPathRequestMatcher("/hello/**") diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java index 1c13a37377..fff0e7cfba 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java @@ -518,8 +518,7 @@ public class FormLoginConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .formLogin((formLogin) -> - formLogin + .formLogin((formLogin) -> formLogin .loginPage("/authenticate") .permitAll() ) @@ -573,15 +572,13 @@ public class FormLoginConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) - .formLogin((formLogin) -> - formLogin + .formLogin((formLogin) -> formLogin .loginProcessingUrl("/loginCheck") .loginPage("/login") .defaultSuccessUrl("/", true) .permitAll() ) - .logout((logout) -> - logout + .logout((logout) -> logout .logoutSuccessUrl("/login") .logoutUrl("/logout") .deleteCookies("JSESSIONID") diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java index 1b68c27628..779754b524 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java @@ -630,8 +630,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .contentTypeOptions(withDefaults()) ); @@ -700,8 +699,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .cacheControl(withDefaults()) ); @@ -753,8 +751,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .xssProtection(withDefaults()) ); @@ -772,11 +769,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() - .xssProtection((xXssConfig) -> - xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) + .xssProtection((xXssConfig) -> xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK) ) ); // @formatter:on @@ -808,8 +803,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .frameOptions((frameOptionsConfig) -> frameOptionsConfig.sameOrigin()) ); return http.build(); @@ -976,11 +970,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() - .httpPublicKeyPinning((hpkp) -> - hpkp + .httpPublicKeyPinning((hpkp) -> hpkp .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=") .reportUri("https://example.net/pkp-report") ) @@ -1035,11 +1027,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() - .contentSecurityPolicy((csp) -> - csp + .contentSecurityPolicy((csp) -> csp .policyDirectives("default-src 'self'; script-src trustedscripts.example.com") .reportOnly() ) @@ -1075,11 +1065,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() - .contentSecurityPolicy((csp) -> - csp.policyDirectives("") + .contentSecurityPolicy((csp) -> csp.policyDirectives("") ) ); return http.build(); @@ -1096,8 +1084,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .contentSecurityPolicy(withDefaults()) ); @@ -1132,8 +1119,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .referrerPolicy(Customizer.withDefaults()) ); @@ -1168,11 +1154,9 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() - .referrerPolicy((referrerPolicy) -> - referrerPolicy.policy(ReferrerPolicy.SAME_ORIGIN) + .referrerPolicy((referrerPolicy) -> referrerPolicy.policy(ReferrerPolicy.SAME_ORIGIN) ) ); return http.build(); @@ -1308,8 +1292,7 @@ public class HeadersConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .headers((headers) -> - headers + .headers((headers) -> headers .defaultsDisabled() .httpStrictTransportSecurity((hstsConfig) -> hstsConfig.preload(true)) ); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java index 747dabafe5..85d7838988 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java @@ -336,8 +336,7 @@ public class HttpSecurityRequestMatchersTests { SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { // @formatter:off http - .securityMatchers((matchers) -> - matchers + .securityMatchers((secure) -> secure .requestMatchers(new MvcRequestMatcher(introspector, "/path")) ) .httpBasic(withDefaults()) @@ -409,8 +408,7 @@ public class HttpSecurityRequestMatchersTests { mvcMatcherBuilder.servletPath("/spring"); // @formatter:off http - .securityMatchers((matchers) -> - matchers + .securityMatchers((secure) -> secure .requestMatchers(mvcMatcherBuilder.pattern("/path")) .requestMatchers("/never-match") ) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java index 930b55b6c5..bd45bfc489 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java @@ -212,8 +212,7 @@ public class JeeConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .jee((jee) -> - jee + .jee((jee) -> jee .mappableRoles("USER") ); return http.build(); @@ -233,8 +232,7 @@ public class JeeConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .jee((jee) -> - jee + .jee((jee) -> jee .mappableAuthorities("ROLE_USER") ); return http.build(); @@ -257,8 +255,7 @@ public class JeeConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .jee((jee) -> - jee + .jee((jee) -> jee .authenticatedUserDetailsService(authenticationUserDetailsService) ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java index b8414c53fd..294b962360 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java @@ -431,8 +431,7 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout((logout) -> - logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class)) + .logout((logout) -> logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class)) ); return http.build(); // @formatter:on @@ -464,8 +463,7 @@ public class LogoutConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout((logout) -> - logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null) + .logout((logout) -> logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null) ); return http.build(); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java index 2f83d45a13..ae7a9ae97f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java @@ -280,8 +280,7 @@ public class NamespaceHttpBasicTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .httpBasic((httpBasicConfig) -> - httpBasicConfig.authenticationDetailsSource(this.authenticationDetailsSource)); + .httpBasic((httpBasicConfig) -> httpBasicConfig.authenticationDetailsSource(this.authenticationDetailsSource)); return http.build(); // @formatter:on } @@ -326,8 +325,7 @@ public class NamespaceHttpBasicTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .httpBasic((httpBasicConfig) -> - httpBasicConfig.authenticationEntryPoint(this.authenticationEntryPoint)); + .httpBasic((httpBasicConfig) -> httpBasicConfig.authenticationEntryPoint(this.authenticationEntryPoint)); return http.build(); // @formatter:on } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java index 7f8858b964..d690d08632 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java @@ -215,8 +215,7 @@ public class NamespaceHttpLogoutTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .logout((logout) -> - logout.deleteCookies("remove") + .logout((logout) -> logout.deleteCookies("remove") .invalidateHttpSession(false) .logoutUrl("/custom-logout") .logoutSuccessUrl("/logout-success") diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java index 67eba03574..ae941164f8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java @@ -133,8 +133,7 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) - .exceptionHandling((exceptionHandling) -> - exceptionHandling.accessDeniedPage("/AccessDeniedPageConfig") + .exceptionHandling((exceptionHandling) -> exceptionHandling.accessDeniedPage("/AccessDeniedPageConfig") ); return http.build(); // @formatter:on @@ -178,8 +177,7 @@ public class NamespaceHttpServerAccessDeniedHandlerTests { .authorizeRequests((authorize) -> authorize .anyRequest().denyAll() ) - .exceptionHandling((exceptionHandling) -> - exceptionHandling.accessDeniedHandler(accessDeniedHandler()) + .exceptionHandling((exceptionHandling) -> exceptionHandling.accessDeniedHandler(accessDeniedHandler()) ); return http.build(); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java index 8241948f98..46d22f931f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java @@ -93,12 +93,10 @@ public class PortMapperConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .requiresChannel((requiresChannel) -> - requiresChannel + .requiresChannel((requiresChannel) -> requiresChannel .anyRequest().requiresSecure() ) - .portMapper((portMapper) -> - portMapper + .portMapper((portMapper) -> portMapper .http(543).mapsTo(123) ); return http.build(); @@ -117,12 +115,10 @@ public class PortMapperConfigurerTests { customPortMapper.setPortMappings(Collections.singletonMap("543", "123")); // @formatter:off http - .requiresChannel((requiresChannel) -> - requiresChannel + .requiresChannel((requiresChannel) -> requiresChannel .anyRequest().requiresSecure() ) - .portMapper((portMapper) -> - portMapper + .portMapper((portMapper) -> portMapper .portMapper(customPortMapper) ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java index 2859889e26..3694cb7cf6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java @@ -560,8 +560,7 @@ public class RememberMeConfigurerTests { .anyRequest().hasRole("USER") ) .formLogin(withDefaults()) - .rememberMe((rememberMe) -> - rememberMe + .rememberMe((rememberMe) -> rememberMe .rememberMeCookieDomain("spring.io") ); return http.build(); @@ -637,8 +636,7 @@ public class RememberMeConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().hasRole("USER") ) - .sessionManagement((sessionManagement) -> - sessionManagement + .sessionManagement((sessionManagement) -> sessionManagement .maximumSessions(1) ) .formLogin(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java index bd1fcdfd20..32e631a3ee 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java @@ -454,8 +454,7 @@ public class RequestCacheConfigurerTests { .anyRequest().authenticated() ) .formLogin(withDefaults()) - .requestCache((requestCache) -> - requestCache + .requestCache((requestCache) -> requestCache .requestCache(new NullRequestCache()) ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java index c6a6f366b4..d28dca2d42 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java @@ -98,12 +98,10 @@ public class RequestMatcherConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .securityMatchers((matchers) -> - matchers + .securityMatchers((secure) -> secure .requestMatchers(new AntPathRequestMatcher("/api/**")) ) - .securityMatchers((matchers) -> - matchers + .securityMatchers((securityMatchers) -> securityMatchers .requestMatchers(new AntPathRequestMatcher("/oauth/**")) ) .authorizeRequests((authorize) -> authorize diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java index ad14a2c5d1..3db5551fa8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java @@ -269,8 +269,7 @@ public class SecurityContextConfigurerTests { // @formatter:off http .formLogin(withDefaults()) - .securityContext((securityContext) -> - securityContext + .securityContext((securityContext) -> securityContext .securityContextRepository(new NullSecurityContextRepository()) ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java index e8465e2a5c..a17270793c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java @@ -359,8 +359,7 @@ public class ServletApiConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .servletApi((servletApi) -> - servletApi + .servletApi((servletApi) -> servletApi .rolePrefix("PERMISSION_") ); return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java index 04ce689e96..9cec841c8b 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java @@ -629,8 +629,7 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement((sessionManagement) -> - sessionManagement + .sessionManagement((sessionManagement) -> sessionManagement .requireExplicitAuthenticationStrategy(false) .sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::newSession) ) @@ -678,10 +677,8 @@ public class SessionManagementConfigurerTests { // @formatter:off http .formLogin(withDefaults()) - .sessionManagement((sessionManagement) -> - sessionManagement - .sessionConcurrency((sessionConcurrency) -> - sessionConcurrency + .sessionManagement((sessionManagement) -> sessionManagement + .sessionConcurrency((sessionConcurrency) -> sessionConcurrency .maximumSessions(1) .maxSessionsPreventsLogin(true) ) @@ -741,8 +738,7 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement((sessionManagement) -> - sessionManagement + .sessionManagement((sessionManagement) -> sessionManagement .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ); return http.build(); @@ -897,8 +893,7 @@ public class SessionManagementConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .sessionManagement((sessionManagement) -> - sessionManagement + .sessionManagement((sessionManagement) -> sessionManagement .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .httpBasic(withDefaults()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java index 7293eb32fa..8841e76258 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java @@ -280,8 +280,7 @@ public class X509ConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .x509((x509) -> - x509 + .x509((x509) -> x509 .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)") ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 6cfbccb1ea..6428609517 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -827,8 +827,7 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository( new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) ); @@ -1029,11 +1028,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository) - .authorizationEndpoint((authorizationEndpoint) -> - authorizationEndpoint + .authorizationEndpoint((authorizationEndpoint) -> authorizationEndpoint .authorizationRequestResolver(this.resolver) ) ); @@ -1056,11 +1053,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository) - .authorizationEndpoint((authorizationEndpoint) -> - authorizationEndpoint + .authorizationEndpoint((authorizationEndpoint) -> authorizationEndpoint .authorizationRedirectStrategy(this.redirectStrategy) ) ); @@ -1083,11 +1078,9 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository(this.clientRegistrationRepository) - .authorizationEndpoint((authorizationEndpoint) -> - authorizationEndpoint + .authorizationEndpoint((authorizationEndpoint) -> authorizationEndpoint .authorizationRedirectStrategy(this.redirectStrategy) ) ); @@ -1159,8 +1152,7 @@ public class OAuth2LoginConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .clientRegistrationRepository( new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION)) .loginPage("/custom-login") @@ -1343,18 +1335,14 @@ public class OAuth2LoginConfigurerTests { .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) - .securityContext((securityContext) -> - securityContext + .securityContext((securityContext) -> securityContext .securityContextRepository(securityContextRepository()) ) - .oauth2Login((oauth2Login) -> - oauth2Login - .tokenEndpoint((tokenEndpoint) -> - tokenEndpoint + .oauth2Login((oauth2) -> oauth2 + .tokenEndpoint((tokenEndpoint) -> tokenEndpoint .accessTokenResponseClient(createOauth2AccessTokenResponseClient()) ) - .userInfoEndpoint((userInfoEndpoint) -> - userInfoEndpoint + .userInfoEndpoint((userInfoEndpoint) -> userInfoEndpoint .userService(createOauth2UserService()) .oidcUserService(createOidcUserService()) ) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index 5dbdfa89de..703243430f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -245,8 +245,7 @@ public class DPoPAuthenticationConfigurerTests { .requestMatchers("/resource2").hasAnyAuthority("SCOPE_resource2.read", "SCOPE_resource2.write") .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer + .oauth2ResourceServer((oauth2) -> oauth2 .jwt(Customizer.withDefaults())); // @formatter:on return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index db701a0080..a7d00de5d0 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1580,8 +1580,7 @@ public class OAuth2ResourceServerConfigurerTests { .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer + .oauth2ResourceServer((oauth2) -> oauth2 .jwt(withDefaults()) ); return http.build(); @@ -1632,10 +1631,8 @@ public class OAuth2ResourceServerConfigurerTests { .requestMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')") .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwkSetUri(this.jwkSetUri) ) ); @@ -2122,10 +2119,8 @@ public class OAuth2ResourceServerConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .decoder(decoder()) ) ); @@ -2386,8 +2381,7 @@ public class OAuth2ResourceServerConfigurerTests { .requestMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read") .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer + .oauth2ResourceServer((oauth2) -> oauth2 .opaqueToken(withDefaults()) ); return http.build(); @@ -2431,10 +2425,8 @@ public class OAuth2ResourceServerConfigurerTests { .authorizeRequests((authorize) -> authorize .anyRequest().authenticated() ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .opaqueToken((opaqueToken) -> - opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .authenticationManager(authenticationProvider()::authenticate) ) ); diff --git a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java index 90ebcc1a2f..386f35bf69 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HeaderSpecTests.java @@ -333,8 +333,7 @@ public class HeaderSpecTests { this.expectedHeaders.set(XXssProtectionServerHttpHeadersWriter.X_XSS_PROTECTION, "0"); // @formatter:off this.http.headers((headers) -> headers - .xssProtection((xssProtection) -> - xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED) + .xssProtection((xssProtection) -> xssProtection.headerValue(XXssProtectionServerHttpHeadersWriter.HeaderValue.DISABLED) )); // @formatter:on assertHeaders(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java index f169f3b843..17d377bd31 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HttpsRedirectSpecTests.java @@ -211,8 +211,7 @@ public class HttpsRedirectSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .redirectToHttps((redirectToHttps) -> - redirectToHttps + .redirectToHttps((redirectToHttps) -> redirectToHttps .httpsRedirectWhen(new PathPatternParserServerWebExchangeMatcher("/secure")) ); // @formatter:on @@ -252,8 +251,7 @@ public class HttpsRedirectSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .redirectToHttps((redirectToHttps) -> - redirectToHttps + .redirectToHttps((redirectToHttps) -> redirectToHttps .portMapper(portMapper()) ); // @formatter:on diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java index b8af150999..45fe167cea 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java @@ -377,8 +377,7 @@ public class OAuth2ClientSpecTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .oauth2Client((oauth2Client) -> - oauth2Client + .oauth2Client((oauth2Client) -> oauth2Client .authenticationConverter(this.authenticationConverter) .authenticationManager(this.manager) .authorizationRequestRepository(this.authorizationRequestRepository)) diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java index e4a6ad711f..33efb51810 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java @@ -986,12 +986,10 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> - exchanges + .authorizeExchange((authorizeExchange) -> authorizeExchange .anyExchange().authenticated() ) - .oauth2Login((oauth2Login) -> - oauth2Login + .oauth2Login((oauth2) -> oauth2 .authenticationConverter(this.authenticationConverter) .authenticationManager(this.manager) .authenticationMatcher(this.matcher) diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java index 2a62230c76..7c8fd3a427 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java @@ -701,14 +701,11 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> - exchanges + .authorizeExchange((authorizeExchange) -> authorizeExchange .anyExchange().hasAuthority("SCOPE_message:read") ) - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .publicKey(publicKey()) ) ); @@ -782,10 +779,8 @@ public class OAuth2ResourceServerSpecTests { String jwkSetUri = mockWebServer().url("/.well-known/jwks.json").toString(); // @formatter:off http - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .jwkSetUri(jwkSetUri) ) ); @@ -879,10 +874,8 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .jwt((jwt) -> - jwt + .oauth2ResourceServer((oauth2) -> oauth2 + .jwt((jwt) -> jwt .authenticationManager(authenticationManager()) ) ); @@ -1078,10 +1071,8 @@ public class OAuth2ResourceServerSpecTests { String introspectionUri = mockWebServer().url("/introspect").toString(); // @formatter:off http - .oauth2ResourceServer((oauth2ResourceServer) -> - oauth2ResourceServer - .opaqueToken((opaqueToken) -> - opaqueToken + .oauth2ResourceServer((oauth2) -> oauth2 + .opaqueToken((opaqueToken) -> opaqueToken .introspectionUri(introspectionUri) .introspectionClientCredentials("client", "secret") ) From a4c338f8a517c332d2ce0cf2c4ccc62ef30793f2 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:29:38 -0600 Subject: [PATCH 410/504] Format authorizeExchange Blocks This commit formats authorizeExchange blocks to use a common variable name and ensure the variable and reference are on the same line. Issue gh-13067 --- .../reactive/WebFluxSecurityConfiguration.java | 2 +- .../config/web/server/ServerHttpSecurity.java | 2 +- .../reactive/EnableWebFluxSecurityTests.java | 2 +- .../ServerHttpSecurityConfigurationTests.java | 4 ++-- .../web/server/AuthorizeExchangeSpecTests.java | 12 ++++++------ .../web/server/ExceptionHandlingSpecTests.java | 12 ++++++------ .../config/web/server/FormLoginTests.java | 16 ++++++++-------- .../config/web/server/LogoutSpecTests.java | 10 +++++----- .../config/web/server/OAuth2LoginTests.java | 10 +++++----- .../server/OAuth2ResourceServerSpecTests.java | 18 +++++++++--------- .../config/web/server/RequestCacheTests.java | 6 +++--- .../web/server/ServerHttpSecurityTests.java | 8 ++++---- .../web/server/SessionManagementSpecTests.java | 10 +++++----- .../pages/reactive/authentication/logout.adoc | 4 ++-- .../authorization/authorize-http-requests.adoc | 2 +- .../pages/reactive/authorization/method.adoc | 2 +- .../pages/reactive/configuration/webflux.adoc | 6 +++--- .../reactive/oauth2/resource-server/jwt.adoc | 12 ++++++------ .../oauth2/resource-server/multitenancy.adoc | 4 ++-- .../oauth2/resource-server/opaque-token.adoc | 10 +++++----- .../reactivex509/CustomX509Configuration.java | 2 +- .../reactivex509/DefaultX509Configuration.java | 2 +- 22 files changed, 78 insertions(+), 78 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java index 0afea13f5a..0187bb7e92 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.java @@ -123,7 +123,7 @@ class WebFluxSecurityConfiguration { * @return */ private SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); + http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); if (isOAuth2Present && OAuth2ClasspathGuard.shouldConfigure(this.context)) { OAuth2ClasspathGuard.configure(this.context, http); } diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index 3e93825f79..a46e7841b3 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -270,7 +270,7 @@ import org.springframework.web.util.pattern.PathPatternParser; * @Bean * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { * http - * .authorizeExchange((exchange) -> exchange.anyExchange().authenticated()) + * .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) * .httpBasic(Customizer.withDefaults()) * .formLogin(); * return http.build(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java index 7275ebf5d6..28e1787f43 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java @@ -377,7 +377,7 @@ public class EnableWebFluxSecurityTests { @Bean SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) { http.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**")) - .authorizeExchange((exchange) -> exchange.anyExchange().denyAll()); + .authorizeExchange((authorize) -> authorize.anyExchange().denyAll()); return http.build(); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTests.java index 4129702b34..5d56a97012 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTests.java @@ -281,7 +281,7 @@ public class ServerHttpSecurityConfigurationTests { SecurityWebFilterChain filterChain(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .formLogin(Customizer.withDefaults()); @@ -300,7 +300,7 @@ public class ServerHttpSecurityConfigurationTests { SecurityWebFilterChain filterChain(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .formLogin((form) -> form diff --git a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java index b4e4839359..658f5666d7 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeSpecTests.java @@ -89,7 +89,7 @@ public class AuthorizeExchangeSpecTests { @Test public void antMatchersWhenPatternsInLambdaThenAnyMethod() { this.http.csrf(ServerHttpSecurity.CsrfSpec::disable) - .authorizeExchange((exchanges) -> exchanges.pathMatchers("/a", "/b").denyAll().anyExchange().permitAll()); + .authorizeExchange((authorize) -> authorize.pathMatchers("/a", "/b").denyAll().anyExchange().permitAll()); WebTestClient client = buildClient(); // @formatter:off client.get() @@ -113,16 +113,16 @@ public class AuthorizeExchangeSpecTests { @Test public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() { - this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/incomplete")); + this.http.authorizeExchange((authorize) -> authorize.pathMatchers("/incomplete")); assertThatIllegalStateException() - .isThrownBy(() -> this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/throws-exception"))); + .isThrownBy(() -> this.http.authorizeExchange((authorize) -> authorize.pathMatchers("/throws-exception"))); } @Test public void anyExchangeWhenFollowedByMatcherThenThrowsException() { assertThatIllegalStateException().isThrownBy(() -> // @formatter:off - this.http.authorizeExchange((exchange) -> exchange + this.http.authorizeExchange((authorize) -> authorize .anyExchange().denyAll() .pathMatchers("/never-reached")) // @formatter:on @@ -131,13 +131,13 @@ public class AuthorizeExchangeSpecTests { @Test public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() { - this.http.authorizeExchange((exchange) -> exchange.pathMatchers("/incomplete")); + this.http.authorizeExchange((authorize) -> authorize.pathMatchers("/incomplete")); assertThatIllegalStateException().isThrownBy(this.http::build); } @Test public void buildWhenMatcherDefinedWithNoAccessInLambdaThenThrowsException() { - this.http.authorizeExchange((exchanges) -> exchanges.pathMatchers("/incomplete")); + this.http.authorizeExchange((authorize) -> authorize.pathMatchers("/incomplete")); assertThatIllegalStateException().isThrownBy(this.http::build); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java index cc38649dc3..e99cd5c5d2 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/ExceptionHandlingSpecTests.java @@ -63,7 +63,7 @@ public class ExceptionHandlingSpecTests { public void requestWhenExceptionHandlingWithDefaultsInLambdaThenDefaultAuthenticationEntryPointUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .exceptionHandling(withDefaults()) @@ -104,7 +104,7 @@ public class ExceptionHandlingSpecTests { public void requestWhenCustomAuthenticationEntryPointInLambdaThenCustomAuthenticationEntryPointUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .exceptionHandling((exceptionHandling) -> exceptionHandling @@ -128,7 +128,7 @@ public class ExceptionHandlingSpecTests { SecurityWebFilterChain securityWebFilter = this.http .csrf((csrf) -> csrf.disable()) .httpBasic(Customizer.withDefaults()) - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasRole("ADMIN")) .exceptionHandling(withDefaults()) .build(); @@ -148,7 +148,7 @@ public class ExceptionHandlingSpecTests { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http .httpBasic(withDefaults()) - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().hasRole("ADMIN") ) .exceptionHandling(withDefaults()) @@ -170,7 +170,7 @@ public class ExceptionHandlingSpecTests { SecurityWebFilterChain securityWebFilter = this.http .csrf((csrf) -> csrf.disable()) .httpBasic(Customizer.withDefaults()) - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasRole("ADMIN")) .exceptionHandling((handling) -> handling .accessDeniedHandler(httpStatusServerAccessDeniedHandler(HttpStatus.BAD_REQUEST))) @@ -191,7 +191,7 @@ public class ExceptionHandlingSpecTests { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http .httpBasic(withDefaults()) - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().hasRole("ADMIN") ) .exceptionHandling((exceptionHandling) -> exceptionHandling diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java index 1fef14dbac..a770ff69c0 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java @@ -69,7 +69,7 @@ public class FormLoginTests { public void defaultLoginPage() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .build(); @@ -100,7 +100,7 @@ public class FormLoginTests { @Test public void formLoginWhenDefaultsInLambdaThenCreatesDefaultLoginPage() { SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .formLogin(withDefaults()) .build(); WebTestClient webTestClient = WebTestClientBuilder.bindToWebFilters(securityWebFilter).build(); @@ -127,7 +127,7 @@ public class FormLoginTests { public void customLoginPage() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/login").permitAll() .anyExchange().authenticated()) .formLogin((login) -> login @@ -155,7 +155,7 @@ public class FormLoginTests { public void formLoginWhenCustomLoginPageInLambdaThenUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .pathMatchers("/login").permitAll() .anyExchange().authenticated() ) @@ -185,7 +185,7 @@ public class FormLoginTests { public void formLoginWhenCustomAuthenticationFailureHandlerThenUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/login", "/failure").permitAll() .anyExchange().authenticated()) .formLogin((login) -> login @@ -212,7 +212,7 @@ public class FormLoginTests { public void formLoginWhenCustomRequiresAuthenticationMatcherThenUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/login", "/sign-in").permitAll() .anyExchange().authenticated()) .formLogin((login) -> login @@ -233,7 +233,7 @@ public class FormLoginTests { public void authenticationSuccess() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin((login) -> login .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/custom"))) @@ -298,7 +298,7 @@ public class FormLoginTests { given(formLoginSecContextRepository.load(any())).willReturn(authentication(token)); // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .securityContextRepository(defaultSecContextRepository) .formLogin((login) -> login diff --git a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java index 22912a2a1d..b4cb5e7d32 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java @@ -44,7 +44,7 @@ public class LogoutSpecTests { public void defaultLogout() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .build(); @@ -78,7 +78,7 @@ public class LogoutSpecTests { public void customLogout() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .logout((logout) -> logout @@ -114,7 +114,7 @@ public class LogoutSpecTests { public void logoutWhenCustomLogoutInLambdaThenCustomLogoutUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .formLogin(withDefaults()) @@ -151,7 +151,7 @@ public class LogoutSpecTests { public void logoutWhenDisabledThenDefaultLogoutPageDoesNotExist() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .logout((logout) -> logout.disable()) @@ -184,7 +184,7 @@ public class LogoutSpecTests { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http .securityContextRepository(repository) - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .logout(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java index 33efb51810..fc158311b4 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java @@ -863,7 +863,7 @@ public class OAuth2LoginTests { http.authenticationManager(authenticationManager); // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .oauth2Login(withDefaults()) .formLogin(withDefaults()); @@ -885,7 +885,7 @@ public class OAuth2LoginTests { http.authenticationManager(authenticationManager); // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .oauth2Login(withDefaults()) .httpBasic(withDefaults()); @@ -954,7 +954,7 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .oauth2Login((login) -> login .authenticationConverter(this.authenticationConverter) @@ -986,7 +986,7 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((authorizeExchange) -> authorizeExchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2Login((oauth2) -> oauth2 @@ -1024,7 +1024,7 @@ public class OAuth2LoginTests { SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .oauth2Login((login) -> login .authenticationConverter(this.authenticationConverter) diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java index 7c8fd3a427..ad44d3372d 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java @@ -682,7 +682,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasAuthority("SCOPE_message:read")) .oauth2ResourceServer((server) -> server .jwt((jwt) -> jwt.publicKey(publicKey()))); @@ -701,7 +701,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((authorizeExchange) -> authorizeExchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasAuthority("SCOPE_message:read") ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -727,7 +727,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasAuthority("SCOPE_message:read")) .oauth2ResourceServer((server) -> server .jwt((jwt) -> jwt.publicKey(this.key))); @@ -833,7 +833,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain authorization(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().denyAll()) .oauth2ResourceServer((server) -> server .jwt((jwt) -> jwt.publicKey(publicKey()))); @@ -899,7 +899,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/*/message/**").hasAnyAuthority("SCOPE_message:read")) .oauth2ResourceServer((server) -> server .authenticationManagerResolver(authenticationManagerResolver())); @@ -957,7 +957,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasAuthority("SCOPE_message:read")) .oauth2ResourceServer((server) -> server .bearerTokenConverter(bearerTokenAuthenticationConverter()) @@ -983,7 +983,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().hasAuthority("message:read")) .oauth2ResourceServer((server) -> server .jwt((jwt) -> jwt @@ -1014,7 +1014,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/authenticated").authenticated() .pathMatchers("/unobtainable").hasAuthority("unobtainable")) .oauth2ResourceServer((server) -> server @@ -1102,7 +1102,7 @@ public class OAuth2ResourceServerSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .oauth2ResourceServer((server) -> server .authenticationManagerResolver(mock(ReactiveAuthenticationManagerResolver.class)) diff --git a/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java b/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java index de9c5d4427..9c7aef9306 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/RequestCacheTests.java @@ -49,7 +49,7 @@ public class RequestCacheTests { public void defaultFormLoginRequestCache() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .build(); @@ -75,7 +75,7 @@ public class RequestCacheTests { public void requestCacheNoOp() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated()) .formLogin(withDefaults()) .requestCache((cache) -> cache @@ -103,7 +103,7 @@ public class RequestCacheTests { public void requestWhenCustomRequestCacheInLambdaThenCustomCacheUsed() { // @formatter:off SecurityWebFilterChain securityWebFilter = this.http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .formLogin(withDefaults()) diff --git a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java index 7521d5925f..0aedcb2de8 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java @@ -191,7 +191,7 @@ public class ServerHttpSecurityTests { @Test public void basicWhenNoCredentialsThenUnauthorized() { - this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off client.get().uri("/") @@ -207,7 +207,7 @@ public class ServerHttpSecurityTests { ServerAuthenticationEntryPoint authenticationEntryPoint = spy( new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)); this.http.httpBasic((basic) -> basic.authenticationEntryPoint(authenticationEntryPoint)); - this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); WebTestClient client = buildClient(); // @formatter:off client.get().uri("/") @@ -228,7 +228,7 @@ public class ServerHttpSecurityTests { ServerAuthenticationFailureHandler.class); this.http.httpBasic((basic) -> basic.authenticationFailureHandler(authenticationFailureHandler)); this.http.httpBasic((basic) -> basic.authenticationManager(authenticationManager)); - this.http.authorizeExchange((exchange) -> exchange.anyExchange().authenticated()); + this.http.authorizeExchange((authorize) -> authorize.anyExchange().authenticated()); given(authenticationManager.authenticate(any())) .willReturn(Mono.error(() -> new BadCredentialsException("bad"))); given(authenticationFailureHandler.onAuthenticationFailure(any(), any())).willReturn(Mono.empty()); @@ -596,7 +596,7 @@ public class ServerHttpSecurityTests { ReactiveClientRegistrationRepository.class); SecurityWebFilterChain securityFilterChain = this.http .oauth2Login((login) -> login.clientRegistrationRepository(clientRegistrationRepository)) - .authorizeExchange((exchange) -> exchange.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .requestCache((c) -> c.requestCache(requestCache)) .build(); WebTestClient client = WebTestClientBuilder.bindToWebFilters(securityFilterChain).build(); diff --git a/config/src/test/java/org/springframework/security/config/web/server/SessionManagementSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/SessionManagementSpecTests.java index 1a380bb6e3..2277351408 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/SessionManagementSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/SessionManagementSpecTests.java @@ -418,7 +418,7 @@ public class SessionManagementSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .formLogin(Customizer.withDefaults()) .sessionManagement((sessionManagement) -> sessionManagement .concurrentSessions((concurrentSessions) -> concurrentSessions @@ -453,7 +453,7 @@ public class SessionManagementSpecTests { DefaultWebSessionManager webSessionManager) { // @formatter:off http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2Login((oauth2Login) -> oauth2Login @@ -493,7 +493,7 @@ public class SessionManagementSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .formLogin(Customizer.withDefaults()) .sessionManagement((sessionManagement) -> sessionManagement .concurrentSessions((concurrentSessions) -> concurrentSessions @@ -516,7 +516,7 @@ public class SessionManagementSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .formLogin((login) -> login .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/")) ) @@ -542,7 +542,7 @@ public class SessionManagementSpecTests { SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { // @formatter:off http - .authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .httpBasic((basic) -> basic .securityContextRepository(new WebSessionServerSecurityContextRepository()) ) diff --git a/docs/modules/ROOT/pages/reactive/authentication/logout.adoc b/docs/modules/ROOT/pages/reactive/authentication/logout.adoc index 26fed89b69..c89fc400ed 100644 --- a/docs/modules/ROOT/pages/reactive/authentication/logout.adoc +++ b/docs/modules/ROOT/pages/reactive/authentication/logout.adoc @@ -24,7 +24,7 @@ SecurityWebFilterChain http(ServerHttpSecurity http) throws Exception { ); http - .authorizeExchange((exchange) -> exchange.anyExchange().authenticated()) + .authorizeExchange((authorize) -> authorize.anyExchange().authenticated()) .logout((logout) -> logout.logoutHandler(logoutHandler)); return http.build(); @@ -40,7 +40,7 @@ fun http(http: ServerHttpSecurity): SecurityWebFilterChain { val customLogoutHandler = DelegatingServerLogoutHandler( SecurityContextServerLogoutHandler(), WebSessionServerLogoutHandler() ) - + return http { authorizeExchange { authorize(anyExchange, authenticated) diff --git a/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc index 21f678acf0..b9226e86e4 100644 --- a/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/reactive/authorization/authorize-http-requests.adoc @@ -15,7 +15,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .httpBasic(withDefaults()) diff --git a/docs/modules/ROOT/pages/reactive/authorization/method.adoc b/docs/modules/ROOT/pages/reactive/authorization/method.adoc index ebc83eef0a..95d0f91af1 100644 --- a/docs/modules/ROOT/pages/reactive/authorization/method.adoc +++ b/docs/modules/ROOT/pages/reactive/authorization/method.adoc @@ -614,7 +614,7 @@ public class SecurityConfig { return http // Demonstrate that method security works // Best practice to use both for defense in depth - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().permitAll() ) .httpBasic(withDefaults()) diff --git a/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc b/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc index 158605ec42..ad17e3093a 100644 --- a/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc +++ b/docs/modules/ROOT/pages/reactive/configuration/webflux.adoc @@ -87,7 +87,7 @@ public class HelloWebfluxSecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .httpBasic(withDefaults()) @@ -161,7 +161,7 @@ static class MultiSecurityHttpConfig { SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) { http .securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**")) <2> - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerSpec::jwt); <3> @@ -171,7 +171,7 @@ static class MultiSecurityHttpConfig { @Bean SecurityWebFilterChain webHttpSecurity(ServerHttpSecurity http) { <4> http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .httpBasic(withDefaults()); <5> diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc index 0d404deb79..7858d29fbe 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/jwt.adoc @@ -128,7 +128,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerSpec::jwt) @@ -170,7 +170,7 @@ import static org.springframework.security.oauth2.core.authorization.OAuth2React @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .pathMatchers("/message/**").access(hasScope("message:read")) .anyExchange().authenticated() ) @@ -254,7 +254,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -302,7 +302,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -691,7 +691,7 @@ import static org.springframework.security.oauth2.core.authorization.OAuth2React @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .mvcMatchers("/contacts/**").access(hasScope("contacts")) .mvcMatchers("/messages/**").access(hasScope("messages")) .anyExchange().authenticated() @@ -762,7 +762,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc index b1353c8cf9..82b1360bef 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/multitenancy.adoc @@ -27,7 +27,7 @@ JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = J .fromTrustedIssuers("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo"); http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -83,7 +83,7 @@ JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get); http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 diff --git a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc index 1293acf8ae..3d3258a831 100644 --- a/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc +++ b/docs/modules/ROOT/pages/reactive/oauth2/resource-server/opaque-token.adoc @@ -176,7 +176,7 @@ Java:: @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::opaqueToken) @@ -221,7 +221,7 @@ public class MyCustomSecurityConfiguration { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .pathMatchers("/messages/**").access(hasScope("message:read")) .anyExchange().authenticated() ) @@ -310,7 +310,7 @@ public class DirectlyConfiguredIntrospectionUri { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -364,7 +364,7 @@ public class DirectlyConfiguredIntrospector { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ) .oauth2ResourceServer((oauth2) -> oauth2 @@ -457,7 +457,7 @@ public class MappedAuthorities { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http - .authorizeExchange((exchange) -> exchange + .authorizeExchange((authorize) -> authorize .pathMatchers("/contacts/**").access(hasScope("contacts")) .pathMatchers("/messages/**").access(hasScope("messages")) .anyExchange().authenticated() diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java index 45679a2ab9..979179488d 100644 --- a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/CustomX509Configuration.java @@ -63,7 +63,7 @@ public class CustomX509Configuration { .principalExtractor(principalExtractor) .authenticationManager(authenticationManager) ) - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ); // @formatter:on diff --git a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java index ea0f34ddc3..15e6562a72 100644 --- a/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java +++ b/docs/src/test/java/org/springframework/security/docs/reactive/authentication/reactivex509/DefaultX509Configuration.java @@ -44,7 +44,7 @@ public class DefaultX509Configuration { // @formatter:off http .x509(Customizer.withDefaults()) - .authorizeExchange((exchanges) -> exchanges + .authorizeExchange((authorize) -> authorize .anyExchange().authenticated() ); // @formatter:on From 3e9d5854104a39035be53e1595e9884fcb01d644 Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sun, 8 Jun 2025 12:56:25 +0700 Subject: [PATCH 411/504] Update Contribution Guidelines About Streams Closes gh-17097 Signed-off-by: Tran Ngoc Nhan --- CONTRIBUTING.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index e0706cea23..b493f2bd6c 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -81,6 +81,9 @@ The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Sty To format the code as well as check the style, run `./gradlew format && ./gradlew check`. +NOTE: Since the Stream API is https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loop, please use it judiciously. +The team may ask you to change it to a `for` loop if the given code is along a hot path. + [[submit-a-pull-request]] === Submit a Pull Request From 396809bf01e0c5bcfa8a21220d8b9f82655ed6a3 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:49:36 -0600 Subject: [PATCH 412/504] Polish Stream Advice Issue gh-17097 --- CONTRIBUTING.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index b493f2bd6c..b992d267bb 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -79,10 +79,10 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize. -To format the code as well as check the style, run `./gradlew format && ./gradlew check`. +Additionally, since Streams are https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loops, please use them judiciously. +The team may ask you to change to a `for` loop if the given code is along a hot path. -NOTE: Since the Stream API is https://github.com/spring-projects/spring-security/issues/7154[much slower] than `for` loop, please use it judiciously. -The team may ask you to change it to a `for` loop if the given code is along a hot path. +To format the code as well as check the style, run `./gradlew format && ./gradlew check`. [[submit-a-pull-request]] === Submit a Pull Request From 46283b3452cba933423baa667b13bbea829d24ae Mon Sep 17 00:00:00 2001 From: Maciej Kowalski Date: Tue, 27 May 2025 14:31:30 +0200 Subject: [PATCH 413/504] Relax ObjectPostProcessor Type Constraints Closes gh-17175 Signed-off-by: Maciej Kowalski --- .../oauth2/client/OAuth2LoginConfigurer.java | 6 +- .../client/OAuth2LoginConfigurerTests.java | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 355e49670b..bed80d38d7 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -404,11 +404,9 @@ public final class OAuth2LoginConfigurer> oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper); oidcAuthorizedClientRefreshedEventListener.setAuthoritiesMapper(userAuthoritiesMapper); } - oidcAuthorizationCodeAuthenticationProvider = this.postProcess(oidcAuthorizationCodeAuthenticationProvider); - http.authenticationProvider(oidcAuthorizationCodeAuthenticationProvider); + http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider)); - oidcAuthorizedClientRefreshedEventListener = this.postProcess(oidcAuthorizedClientRefreshedEventListener); - registerDelegateApplicationListener(oidcAuthorizedClientRefreshedEventListener); + registerDelegateApplicationListener(this.postProcess(oidcAuthorizedClientRefreshedEventListener)); configureOidcUserRefreshedEventListener(http); } else { diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 9895beaded..8103ea1817 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -43,7 +43,10 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -52,6 +55,7 @@ import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.context.DelegatingApplicationListener; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -214,6 +218,28 @@ public class OAuth2LoginConfigurerTests { .hasToString("OAUTH2_USER"); } + // gh-17175 + @Test + public void postProcessorSucceedsWhenProcessorReturnsAuthenticationProvider() throws Exception { + loadConfig(OAuth2LoginConfigCustomWithPostProcessor.class); + // setup authorization request + OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); + this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.request, this.response); + // setup authentication parameters + this.request.setParameter("code", "code123"); + this.request.setParameter("state", authorizationRequest.getState()); + // perform test + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + // assertions + Authentication authentication = this.securityContextRepository + .loadContext(new HttpRequestResponseHolder(this.request, this.response)) + .getAuthentication(); + assertThat(authentication.getAuthorities()).hasSize(1); + assertThat(authentication.getAuthorities()).first() + .isInstanceOf(OAuth2UserAuthority.class) + .hasToString("OAUTH2_USER"); + } + @Test public void requestWhenCustomSecurityContextHolderStrategyThenUses() throws Exception { loadConfig(OAuth2LoginConfig.class, SecurityContextChangedListenerConfig.class); @@ -1307,6 +1333,56 @@ public class OAuth2LoginConfigurerTests { } + @Configuration + @EnableWebSecurity + static class OAuth2LoginConfigCustomWithPostProcessor + extends CommonLambdaSecurityFilterChainConfig { + + private ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + GOOGLE_CLIENT_REGISTRATION); + + OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class); + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .oauth2Login((oauth2Login) -> + oauth2Login + .clientRegistrationRepository(this.clientRegistrationRepository) +// .authorizedClientRepository(this.authorizedClientRepository) + .withObjectPostProcessor(new CustomProcessor()) + ); + // @formatter:on + return super.configureFilterChain(http); + } + + class CustomProcessor implements ObjectPostProcessor { + @Override + public O postProcess(O object) { + AuthenticationProvider p = new NoopWrapperProvider(object); + + return (O) p; + } + } + + record NoopWrapperProvider( + AuthenticationProvider delegate + ) implements AuthenticationProvider { + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return delegate.authenticate(authentication); + } + + @Override + public boolean supports(Class authentication) { + return delegate.supports(authentication); + } + } + + } + private abstract static class CommonSecurityFilterChainConfig { SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception { From 9f88ef83eb22068d7c8d58d33d75f081ac559998 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 20 Jun 2025 13:20:33 -0600 Subject: [PATCH 414/504] Polish Post-Processor Test Issue gh-17175 Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com> --- .../client/OAuth2LoginConfigurerTests.java | 96 +++++++++---------- 1 file changed, 43 insertions(+), 53 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java index 8103ea1817..d277fc52a3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; @@ -45,17 +46,16 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.event.AuthenticationSuccessEvent; -import org.springframework.security.config.Customizer; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurerTests.OAuth2LoginConfigCustomWithPostProcessor.SpyObjectPostProcessor; import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.context.DelegatingApplicationListener; import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -218,28 +218,6 @@ public class OAuth2LoginConfigurerTests { .hasToString("OAUTH2_USER"); } - // gh-17175 - @Test - public void postProcessorSucceedsWhenProcessorReturnsAuthenticationProvider() throws Exception { - loadConfig(OAuth2LoginConfigCustomWithPostProcessor.class); - // setup authorization request - OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); - this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.request, this.response); - // setup authentication parameters - this.request.setParameter("code", "code123"); - this.request.setParameter("state", authorizationRequest.getState()); - // perform test - this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); - // assertions - Authentication authentication = this.securityContextRepository - .loadContext(new HttpRequestResponseHolder(this.request, this.response)) - .getAuthentication(); - assertThat(authentication.getAuthorities()).hasSize(1); - assertThat(authentication.getAuthorities()).first() - .isInstanceOf(OAuth2UserAuthority.class) - .hasToString("OAUTH2_USER"); - } - @Test public void requestWhenCustomSecurityContextHolderStrategyThenUses() throws Exception { loadConfig(OAuth2LoginConfig.class, SecurityContextChangedListenerConfig.class); @@ -735,6 +713,22 @@ public class OAuth2LoginConfigurerTests { verifyNoInteractions(clientRegistrationRepository, authorizedClientRepository); } + // gh-17175 + @Test + public void oauth2LoginWhenAuthenticationProviderPostProcessorThenUses() throws Exception { + loadConfig(OAuth2LoginConfigCustomWithPostProcessor.class); + // setup authorization request + OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); + this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.request, this.response); + // setup authentication parameters + this.request.setParameter("code", "code123"); + this.request.setParameter("state", authorizationRequest.getState()); + // perform test + this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain); + // assertions + verify(this.context.getBean(SpyObjectPostProcessor.class).spy).authenticate(any()); + } + private void loadConfig(Class... configs) { AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); applicationContext.register(configs); @@ -1335,50 +1329,46 @@ public class OAuth2LoginConfigurerTests { @Configuration @EnableWebSecurity - static class OAuth2LoginConfigCustomWithPostProcessor - extends CommonLambdaSecurityFilterChainConfig { + static class OAuth2LoginConfigCustomWithPostProcessor { - private ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( + private final ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository( GOOGLE_CLIENT_REGISTRATION); - OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class); + private final ObjectPostProcessor postProcessor = new SpyObjectPostProcessor(); @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http - .oauth2Login((oauth2Login) -> - oauth2Login - .clientRegistrationRepository(this.clientRegistrationRepository) -// .authorizedClientRepository(this.authorizedClientRepository) - .withObjectPostProcessor(new CustomProcessor()) - ); + .oauth2Login((oauth2Login) -> oauth2Login + .clientRegistrationRepository(this.clientRegistrationRepository) + .withObjectPostProcessor(this.postProcessor) + ); // @formatter:on - return super.configureFilterChain(http); + return http.build(); } - class CustomProcessor implements ObjectPostProcessor { + @Bean + ObjectPostProcessor mockPostProcessor() { + return this.postProcessor; + } + + @Bean + HttpSessionOAuth2AuthorizationRequestRepository oauth2AuthorizationRequestRepository() { + return new HttpSessionOAuth2AuthorizationRequestRepository(); + } + + static class SpyObjectPostProcessor implements ObjectPostProcessor { + + AuthenticationProvider spy; + @Override public O postProcess(O object) { - AuthenticationProvider p = new NoopWrapperProvider(object); - - return (O) p; - } - } - - record NoopWrapperProvider( - AuthenticationProvider delegate - ) implements AuthenticationProvider { - - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - return delegate.authenticate(authentication); + O spy = Mockito.spy(object); + this.spy = spy; + return spy; } - @Override - public boolean supports(Class authentication) { - return delegate.supports(authentication); - } } } From 90ddb00c00ef9fa7741442afe017aecd0f53a9e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 03:28:29 +0000 Subject: [PATCH 415/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.3.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.3.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.3/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.3) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.3.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..1a06868862 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.3.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 3fd697f9a6b6bc6a9afc1116a2a93a4d89463ed1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 03:30:22 +0000 Subject: [PATCH 416/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..aa4211b8dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-maven-resolver = "1.9.23" From d26d76ecb352bc0da20f0e91bec70f6a1f24e76d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 03:30:42 +0000 Subject: [PATCH 417/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..e4ebb001fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 78d894a4ad13e9e8ec0070511af710ff193d63ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 04:11:38 +0000 Subject: [PATCH 418/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..7197d56f69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From 6b430c94be9c46d3b44e7a792d2451fa5439bf49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 04:15:51 +0000 Subject: [PATCH 419/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a12ae45547 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From c9a895920841d6c17008b84203dfa86e7d4ecebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 04:29:28 +0000 Subject: [PATCH 420/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..c465d30087 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From ed8dafc03506063a0ed6b3a2024e72d9b6fcaec0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:51:31 +0000 Subject: [PATCH 421/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 948049521fa14b6b14d1acb3f49f2d20a4579d01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:56:47 +0000 Subject: [PATCH 422/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..0475e149f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 59374ec03bd2c28ec830412d332c94e51e4c2183 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:57:02 +0000 Subject: [PATCH 423/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 5a861d69fd8c135658a21f5a7b5a200e7c5ad1a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:57:19 +0000 Subject: [PATCH 424/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 3fb987ed17aa7dc527fd91794197f1570581882a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:58:18 +0000 Subject: [PATCH 425/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.3.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.3.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.3/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.3) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.3.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..1a06868862 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.3.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From fb6d29759cb098ca4526fea2a2e7ef0a45f8a20e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 03:58:33 +0000 Subject: [PATCH 426/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..e4ebb001fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 054909694b576bfd689d9ca5f5ea037eefefc826 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:03:54 +0000 Subject: [PATCH 427/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..27a1d5afc5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From bca18d78af4f540d2ad97ac64b2e69511e7e13a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:07:24 +0000 Subject: [PATCH 428/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..7197d56f69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From a8bd1d0143ad5f1e4cb06be3d319f1bb459411c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:08:03 +0000 Subject: [PATCH 429/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..aa4211b8dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-maven-resolver = "1.9.23" From 23fb0e0fc8d590694e9f0a0e17610f42470beb2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:08:04 +0000 Subject: [PATCH 430/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 52ffe56d73aa285eaf85a30b1eb48915c113b715 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:12:08 +0000 Subject: [PATCH 431/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..c465d30087 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From d18909c2d4d5916165f3f50577eb5e2ed17c0ffb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:14:18 +0000 Subject: [PATCH 432/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..760e98560c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 22ca7c9e131837caad98ac9af268d46e3c1f7baf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:22:03 +0000 Subject: [PATCH 433/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From edfae341780b8f9728a9131ee1618c4b07b909d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:28:50 +0000 Subject: [PATCH 434/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..a12a48f9f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 527946873d34628d1ef4dc0bed7a44df278fc159 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:29:03 +0000 Subject: [PATCH 435/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 8c8fb33c00bea896fec5628ae486ef7783209c0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:29:10 +0000 Subject: [PATCH 436/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..98c4e279d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 8f49e0a148469e3d3016ceab63194fc4ccb0cdc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:35:09 +0000 Subject: [PATCH 437/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a12ae45547 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From f8e3c7bccf9374f97a81d7c6b2b3c61af780736c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:35:21 +0000 Subject: [PATCH 438/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 7844b4db5cead2f2ffde4fe4a4c7241e63aa7d13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:40:37 +0000 Subject: [PATCH 439/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From a74ce06dae93e51760abae6e81ccb96b65a38c4b Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sun, 22 Jun 2025 05:17:54 +0700 Subject: [PATCH 440/504] Remove JwtIssuer(Reactive)AuthenticationManagerResolver deprecations Signed-off-by: Tran Ngoc Nhan --- .../OAuth2ResourceServerConfigurerTests.java | 4 +- .../web/OAuth2ResourceServerDslTests.kt | 2 +- .../ServerOAuth2ResourceServerDslTests.kt | 2 +- ...nDefinitionParserTests-MultipleIssuers.xml | 5 +- ...wtIssuerAuthenticationManagerResolver.java | 24 -- ...ReactiveAuthenticationManagerResolver.java | 24 -- ...icationManagerResolverDeprecatedTests.java | 259 ----------------- ...icationManagerResolverDeprecatedTests.java | 263 ------------------ 8 files changed, 7 insertions(+), 576 deletions(-) delete mode 100644 oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverDeprecatedTests.java delete mode 100644 oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverDeprecatedTests.java diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index a7d00de5d0..d49520c56e 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -2559,8 +2559,8 @@ public class OAuth2ResourceServerConfigurerTests { SecurityFilterChain filterChain(HttpSecurity http) throws Exception { String issuerOne = this.web.url("/issuerOne").toString(); String issuerTwo = this.web.url("/issuerTwo").toString(); - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - issuerOne, issuerTwo); + JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = JwtIssuerAuthenticationManagerResolver + .fromTrustedIssuers(issuerOne, issuerTwo); // @formatter:off http .oauth2ResourceServer((server) -> server diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2ResourceServerDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2ResourceServerDslTests.kt index c0631d162a..85c136474a 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2ResourceServerDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/OAuth2ResourceServerDslTests.kt @@ -223,7 +223,7 @@ class OAuth2ResourceServerDslTests { companion object { val RESOLVER: AuthenticationManagerResolver = - JwtIssuerAuthenticationManagerResolver("issuer") + JwtIssuerAuthenticationManagerResolver.fromTrustedIssuers ("issuer") } @Bean diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerOAuth2ResourceServerDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerOAuth2ResourceServerDslTests.kt index c7c3822481..28da159047 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerOAuth2ResourceServerDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerOAuth2ResourceServerDslTests.kt @@ -247,7 +247,7 @@ class ServerOAuth2ResourceServerDslTests { open class AuthenticationManagerResolverConfig { companion object { - val RESOLVER: ReactiveAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver("issuer") + val RESOLVER: ReactiveAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver.fromTrustedIssuers("issuer") } @Bean diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml index 4ab6ff7517..cba1d26936 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-MultipleIssuers.xml @@ -22,8 +22,9 @@ http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> - + class="org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver" + factory-method="fromTrustedIssuers"> + ${issuer-one} ${issuer-two} diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java index de1bda32a7..520028d0db 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java @@ -63,30 +63,6 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat private final AuthenticationManager authenticationManager; - /** - * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided - * parameters - * @param trustedIssuers an array of trusted issuers - * @deprecated use {@link #fromTrustedIssuers(String...)} - */ - @Deprecated(since = "6.2", forRemoval = true) - public JwtIssuerAuthenticationManagerResolver(String... trustedIssuers) { - this(Set.of(trustedIssuers)); - } - - /** - * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided - * parameters - * @param trustedIssuers a collection of trusted issuers - * @deprecated use {@link #fromTrustedIssuers(Collection)} - */ - @Deprecated(since = "6.2", forRemoval = true) - public JwtIssuerAuthenticationManagerResolver(Collection trustedIssuers) { - Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); - this.authenticationManager = new ResolvingAuthenticationManager( - new TrustedIssuerJwtAuthenticationManagerResolver(Set.copyOf(trustedIssuers)::contains)); - } - /** * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided * parameters diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java index b764e4ca76..9ed52c368b 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java @@ -68,30 +68,6 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver private final ReactiveAuthenticationManager authenticationManager; - /** - * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the - * provided parameters - * @param trustedIssuers an array of trusted issuers - * @deprecated use {@link #fromTrustedIssuers(String...)} - */ - @Deprecated(since = "6.2", forRemoval = true) - public JwtIssuerReactiveAuthenticationManagerResolver(String... trustedIssuers) { - this(Set.of(trustedIssuers)); - } - - /** - * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the - * provided parameters - * @param trustedIssuers a collection of trusted issuers - * @deprecated use {@link #fromTrustedIssuers(Collection)} - */ - @Deprecated(since = "6.2", forRemoval = true) - public JwtIssuerReactiveAuthenticationManagerResolver(Collection trustedIssuers) { - Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); - this.authenticationManager = new ResolvingAuthenticationManager( - new TrustedIssuerJwtAuthenticationManagerResolver(Set.copyOf(trustedIssuers)::contains)); - } - /** * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the * provided parameters diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverDeprecatedTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverDeprecatedTests.java deleted file mode 100644 index 8b58d68dd6..0000000000 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverDeprecatedTests.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.oauth2.server.resource.authentication; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSObject; -import com.nimbusds.jose.Payload; -import com.nimbusds.jose.crypto.RSASSASigner; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.PlainJWT; -import net.minidev.json.JSONObject; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.jupiter.api.Test; - -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationManagerResolver; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.jose.TestKeys; -import org.springframework.security.oauth2.jwt.JwtClaimNames; -import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver.TrustedIssuerJwtAuthenticationManagerResolver; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.BDDMockito.mock; -import static org.mockito.BDDMockito.verify; - -/** - * Tests for {@link JwtIssuerAuthenticationManagerResolver} - * - * @deprecated Superseded by {@link JwtIssuerAuthenticationManagerResolverTests} - */ -@Deprecated -public class JwtIssuerAuthenticationManagerResolverDeprecatedTests { - - private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n" + " \"issuer\": \"%s\", \n" - + " \"jwks_uri\": \"%s/.well-known/jwks.json\" \n" + "}"; - - private static final String JWK_SET = "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"n\":\"3FlqJr5TRskIQIgdE3Dd7D9lboWdcTUT8a-fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRvc5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4_1tfRgG6ii4Uhxh6iI8qNMJQX-fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2kJdJ_ZIV-WW4noDdzpKqHcwmB8FsrumlVY_DNVvUSDIipiq9PbP4H99TXN1o746oRaNa07rq1hoCgMSSy-85SagCoxlmyE-D-of9SsMY8Ol9t0rdzpobBuhyJ_o5dfvjKw\"}]}"; - - private String jwt = jwt("iss", "trusted"); - - private String evil = jwt("iss", "\""); - - private String noIssuer = jwt("sub", "sub"); - - @Test - public void resolveWhenUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - server.start(); - String issuer = server.url("").toString(); - // @formatter:off - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer) - )); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET) - ); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET) - ); - // @formatter:on - JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), - new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); - jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - issuer); - Authentication token = withBearerToken(jws.serialize()); - AuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null); - assertThat(authenticationManager).isNotNull(); - Authentication authentication = authenticationManager.authenticate(token); - assertThat(authentication.isAuthenticated()).isTrue(); - } - } - - @Test - public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - server.start(); - String issuer = server.url("").toString(); - // @formatter:off - server.enqueue(new MockResponse().setResponseCode(500) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)) - ); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)) - ); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET) - ); - // @formatter:on - JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), - new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); - jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - issuer); - Authentication token = withBearerToken(jws.serialize()); - AuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null); - assertThat(authenticationManager).isNotNull(); - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> authenticationManager.authenticate(token)); - Authentication authentication = authenticationManager.authenticate(token); - assertThat(authentication.isAuthenticated()).isTrue(); - } - } - - @Test - public void resolveWhenUsingSameIssuerThenReturnsSameAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - String issuer = server.url("").toString(); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET)); - TrustedIssuerJwtAuthenticationManagerResolver resolver = new TrustedIssuerJwtAuthenticationManagerResolver( - (iss) -> iss.equals(issuer)); - AuthenticationManager authenticationManager = resolver.resolve(issuer); - AuthenticationManager cachedAuthenticationManager = resolver.resolve(issuer); - assertThat(authenticationManager).isSameAs(cachedAuthenticationManager); - } - } - - @Test - public void resolveWhenUsingUntrustedIssuerThenException() { - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - "other", "issuers"); - Authentication token = withBearerToken(this.jwt); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null).authenticate(token)) - .withMessageContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverThenUses() { - AuthenticationManager authenticationManager = mock(AuthenticationManager.class); - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - (issuer) -> authenticationManager); - Authentication token = withBearerToken(this.jwt); - authenticationManagerResolver.resolve(null).authenticate(token); - verify(authenticationManager).authenticate(token); - } - - @Test - public void resolveWhenUsingExternalSourceThenRespondsToChanges() { - Authentication token = withBearerToken(this.jwt); - Map authenticationManagers = new HashMap<>(); - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - authenticationManagers::get); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null).authenticate(token)) - .withMessageContaining("Invalid issuer"); - // @formatter:on - AuthenticationManager authenticationManager = mock(AuthenticationManager.class); - authenticationManagers.put("trusted", authenticationManager); - authenticationManagerResolver.resolve(null).authenticate(token); - verify(authenticationManager).authenticate(token); - authenticationManagers.clear(); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null).authenticate(token)) - .withMessageContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenBearerTokenMalformedThenException() { - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken("jwt"); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null).authenticate(token)) - .withMessageNotContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenBearerTokenNoIssuerThenException() { - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken(this.noIssuer); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null).authenticate(token)) - .withMessageContaining("Missing issuer"); - // @formatter:on - } - - @Test - public void resolveWhenBearerTokenEvilThenGenericException() { - JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken(this.evil); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver - .resolve(null).authenticate(token) - ) - .withMessage("Invalid issuer"); - // @formatter:on - } - - @Test - public void constructorWhenNullOrEmptyIssuersThenException() { - assertThatIllegalArgumentException() - .isThrownBy(() -> new JwtIssuerAuthenticationManagerResolver((Collection) null)); - assertThatIllegalArgumentException() - .isThrownBy(() -> new JwtIssuerAuthenticationManagerResolver(Collections.emptyList())); - } - - @Test - public void constructorWhenNullAuthenticationManagerResolverThenException() { - assertThatIllegalArgumentException() - .isThrownBy(() -> new JwtIssuerAuthenticationManagerResolver((AuthenticationManagerResolver) null)); - } - - private Authentication withBearerToken(String token) { - return new BearerTokenAuthenticationToken(token); - } - - private String jwt(String claim, String value) { - PlainJWT jwt = new PlainJWT(new JWTClaimsSet.Builder().claim(claim, value).build()); - return jwt.serialize(); - } - -} diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverDeprecatedTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverDeprecatedTests.java deleted file mode 100644 index ee81881420..0000000000 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverDeprecatedTests.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2002-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.oauth2.server.resource.authentication; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSObject; -import com.nimbusds.jose.Payload; -import com.nimbusds.jose.crypto.RSASSASigner; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.PlainJWT; -import net.minidev.json.JSONObject; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.jose.TestKeys; -import org.springframework.security.oauth2.jwt.JwtClaimNames; -import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerReactiveAuthenticationManagerResolver.TrustedIssuerJwtAuthenticationManagerResolver; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.BDDMockito.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.mock; -import static org.mockito.BDDMockito.verify; - -/** - * Tests for {@link JwtIssuerReactiveAuthenticationManagerResolver} - * - * @deprecated Superseded by {@link JwtIssuerReactiveAuthenticationManagerResolverTests} - */ -@Deprecated -public class JwtIssuerReactiveAuthenticationManagerResolverDeprecatedTests { - - // @formatter:off - private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n" - + " \"issuer\": \"%s\", \n" - + " \"jwks_uri\": \"%s/.well-known/jwks.json\" \n" - + "}"; - // @formatter:on - - private static final String JWK_SET = "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"n\":\"3FlqJr5TRskIQIgdE3Dd7D9lboWdcTUT8a-fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRvc5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4_1tfRgG6ii4Uhxh6iI8qNMJQX-fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2kJdJ_ZIV-WW4noDdzpKqHcwmB8FsrumlVY_DNVvUSDIipiq9PbP4H99TXN1o746oRaNa07rq1hoCgMSSy-85SagCoxlmyE-D-of9SsMY8Ol9t0rdzpobBuhyJ_o5dfvjKw\"}]}"; - - private String jwt = jwt("iss", "trusted"); - - private String evil = jwt("iss", "\""); - - private String noIssuer = jwt("sub", "sub"); - - @Test - public void resolveWhenUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - String issuer = server.url("").toString(); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET)); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET)); - JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), - new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); - jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - issuer); - ReactiveAuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null).block(); - assertThat(authenticationManager).isNotNull(); - BearerTokenAuthenticationToken token = withBearerToken(jws.serialize()); - Authentication authentication = authenticationManager.authenticate(token).block(); - assertThat(authentication).isNotNull(); - assertThat(authentication.isAuthenticated()).isTrue(); - } - } - - // gh-10444 - @Test - public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - String issuer = server.url("").toString(); - // @formatter:off - server.enqueue(new MockResponse().setResponseCode(500).setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); - server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); - server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") - .setBody(JWK_SET)); - // @formatter:on - JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), - new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); - jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - issuer); - ReactiveAuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null).block(); - assertThat(authenticationManager).isNotNull(); - Authentication token = withBearerToken(jws.serialize()); - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> authenticationManager.authenticate(token).block()); - Authentication authentication = authenticationManager.authenticate(token).block(); - assertThat(authentication.isAuthenticated()).isTrue(); - } - } - - @Test - public void resolveWhenUsingSameIssuerThenReturnsSameAuthenticationManager() throws Exception { - try (MockWebServer server = new MockWebServer()) { - String issuer = server.url("").toString(); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); - server.enqueue(new MockResponse().setResponseCode(200) - .setHeader("Content-Type", "application/json") - .setBody(JWK_SET)); - TrustedIssuerJwtAuthenticationManagerResolver resolver = new TrustedIssuerJwtAuthenticationManagerResolver( - (iss) -> iss.equals(issuer)); - ReactiveAuthenticationManager authenticationManager = resolver.resolve(issuer).block(); - ReactiveAuthenticationManager cachedAuthenticationManager = resolver.resolve(issuer).block(); - assertThat(authenticationManager).isSameAs(cachedAuthenticationManager); - } - } - - @Test - public void resolveWhenUsingUntrustedIssuerThenException() { - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - "other", "issuers"); - Authentication token = withBearerToken(this.jwt); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((authenticationManager) -> authenticationManager.authenticate(token)) - .block()) - .withMessageContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverThenUses() { - Authentication token = withBearerToken(this.jwt); - ReactiveAuthenticationManager authenticationManager = mock(ReactiveAuthenticationManager.class); - given(authenticationManager.authenticate(token)).willReturn(Mono.empty()); - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - (issuer) -> Mono.just(authenticationManager)); - authenticationManagerResolver.resolve(null).flatMap((manager) -> manager.authenticate(token)).block(); - verify(authenticationManager).authenticate(any()); - } - - @Test - public void resolveWhenUsingExternalSourceThenRespondsToChanges() { - Authentication token = withBearerToken(this.jwt); - Map authenticationManagers = new HashMap<>(); - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - (issuer) -> Mono.justOrEmpty(authenticationManagers.get(issuer))); - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((manager) -> manager.authenticate(token)) - .block()) - .withMessageContaining("Invalid issuer"); - ReactiveAuthenticationManager authenticationManager = mock(ReactiveAuthenticationManager.class); - given(authenticationManager.authenticate(token)).willReturn(Mono.empty()); - authenticationManagers.put("trusted", authenticationManager); - authenticationManagerResolver.resolve(null).flatMap((manager) -> manager.authenticate(token)).block(); - verify(authenticationManager).authenticate(token); - authenticationManagers.clear(); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((manager) -> manager.authenticate(token)) - .block()) - .withMessageContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenBearerTokenMalformedThenException() { - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken("jwt"); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((manager) -> manager.authenticate(token)) - .block()) - .withMessageNotContaining("Invalid issuer"); - // @formatter:on - } - - @Test - public void resolveWhenBearerTokenNoIssuerThenException() { - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken(this.noIssuer); - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((manager) -> manager.authenticate(token)) - .block()) - .withMessageContaining("Missing issuer"); - } - - @Test - public void resolveWhenBearerTokenEvilThenGenericException() { - JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( - "trusted"); - Authentication token = withBearerToken(this.evil); - // @formatter:off - assertThatExceptionOfType(OAuth2AuthenticationException.class) - .isThrownBy(() -> authenticationManagerResolver.resolve(null) - .flatMap((manager) -> manager.authenticate(token)) - .block()) - .withMessage("Invalid token"); - // @formatter:on - } - - @Test - public void constructorWhenNullOrEmptyIssuersThenException() { - assertThatIllegalArgumentException() - .isThrownBy(() -> new JwtIssuerReactiveAuthenticationManagerResolver((Collection) null)); - assertThatIllegalArgumentException() - .isThrownBy(() -> new JwtIssuerReactiveAuthenticationManagerResolver(Collections.emptyList())); - } - - @Test - public void constructorWhenNullAuthenticationManagerResolverThenException() { - assertThatIllegalArgumentException().isThrownBy( - () -> new JwtIssuerReactiveAuthenticationManagerResolver((ReactiveAuthenticationManagerResolver) null)); - } - - private String jwt(String claim, String value) { - PlainJWT jwt = new PlainJWT(new JWTClaimsSet.Builder().claim(claim, value).build()); - return jwt.serialize(); - } - - private BearerTokenAuthenticationToken withBearerToken(String token) { - return new BearerTokenAuthenticationToken(token); - } - -} From e686ac6b11ced611bb47c26c06206e906fd649db Mon Sep 17 00:00:00 2001 From: Tran Ngoc Nhan Date: Sun, 22 Jun 2025 18:38:56 +0700 Subject: [PATCH 441/504] Remove AbstractSecurityWebSocketMessageBrokerConfigurer Signed-off-by: Tran Ngoc Nhan --- ...urityWebSocketMessageBrokerConfigurer.java | 286 ------- ...SocketMessageBrokerConfigurerDocTests.java | 178 ----- ...WebSocketMessageBrokerConfigurerTests.java | 733 ------------------ ...ssageBrokerSecurityConfigurationTests.java | 32 - .../pages/servlet/integrations/websocket.adoc | 84 -- etc/checkstyle/checkstyle-suppressions.xml | 1 - 6 files changed, 1314 deletions(-) delete mode 100644 config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java delete mode 100644 config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java delete mode 100644 config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java deleted file mode 100644 index cd2baed733..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.socket; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; -import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.expression.SecurityExpressionHandler; -import org.springframework.security.access.vote.AffirmativeBased; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; -import org.springframework.security.messaging.access.expression.MessageExpressionVoter; -import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; -import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource; -import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver; -import org.springframework.security.messaging.context.SecurityContextChannelInterceptor; -import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; -import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.Assert; -import org.springframework.util.PathMatcher; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.server.HandshakeInterceptor; -import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler; -import org.springframework.web.socket.sockjs.SockJsService; -import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler; -import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService; - -/** - * Allows configuring WebSocket Authorization. - * - *

- * For example: - *

- * - *
- * @Configuration
- * public class WebSocketSecurityConfig extends
- * 		AbstractSecurityWebSocketMessageBrokerConfigurer {
- *
- * 	@Override
- * 	protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
- * 		messages.simpDestMatchers("/user/queue/errors").permitAll()
- * 				.simpDestMatchers("/admin/**").hasRole("ADMIN").anyMessage()
- * 				.authenticated();
- * 	}
- * }
- * 
- * - * @author Rob Winch - * @since 4.0 - * @see WebSocketMessageBrokerSecurityConfiguration - * @deprecated Use {@link EnableWebSocketSecurity} instead - */ -@Order(Ordered.HIGHEST_PRECEDENCE + 100) -@Import(ObjectPostProcessorConfiguration.class) -@Deprecated -public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer - implements WebSocketMessageBrokerConfigurer, SmartInitializingSingleton { - - private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry(); - - private SecurityExpressionHandler> defaultExpressionHandler = new DefaultMessageSecurityExpressionHandler<>(); - - private SecurityExpressionHandler> expressionHandler; - - private ApplicationContext context; - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - } - - @Override - public void addArgumentResolvers(List argumentResolvers) { - argumentResolvers.add(new AuthenticationPrincipalArgumentResolver()); - } - - @Override - public final void configureClientInboundChannel(ChannelRegistration registration) { - ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class); - registration.interceptors(this.context.getBean(SecurityContextChannelInterceptor.class)); - if (!sameOriginDisabled()) { - registration.interceptors(this.context.getBean(CsrfChannelInterceptor.class)); - } - if (this.inboundRegistry.containsMapping()) { - registration.interceptors(inboundChannelSecurity); - } - customizeClientInboundChannel(registration); - } - - private PathMatcher getDefaultPathMatcher() { - try { - return this.context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher(); - } - catch (NoSuchBeanDefinitionException ex) { - return new AntPathMatcher(); - } - } - - /** - *

- * Determines if a CSRF token is required for connecting. This protects against remote - * sites from connecting to the application and being able to read/write data over the - * connection. The default is false (the token is required). - *

- *

- * Subclasses can override this method to disable CSRF protection - *

- * @return false if a CSRF token is required for connecting, else true - */ - protected boolean sameOriginDisabled() { - return false; - } - - /** - * Allows subclasses to customize the configuration of the {@link ChannelRegistration} - * . - * @param registration the {@link ChannelRegistration} to customize - */ - protected void customizeClientInboundChannel(ChannelRegistration registration) { - } - - @Bean - public CsrfChannelInterceptor csrfChannelInterceptor() { - return new CsrfChannelInterceptor(); - } - - @Bean - public ChannelSecurityInterceptor inboundChannelSecurity( - MessageSecurityMetadataSource messageSecurityMetadataSource) { - ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor( - messageSecurityMetadataSource); - MessageExpressionVoter voter = new MessageExpressionVoter<>(); - voter.setExpressionHandler(getMessageExpressionHandler()); - List> voters = new ArrayList<>(); - voters.add(voter); - AffirmativeBased manager = new AffirmativeBased(voters); - channelSecurityInterceptor.setAccessDecisionManager(manager); - return channelSecurityInterceptor; - } - - @Bean - public SecurityContextChannelInterceptor securityContextChannelInterceptor() { - return new SecurityContextChannelInterceptor(); - } - - @Bean - public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() { - this.inboundRegistry.expressionHandler(getMessageExpressionHandler()); - configureInbound(this.inboundRegistry); - return this.inboundRegistry.createMetadataSource(); - } - - /** - * @param messages - */ - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - } - - @Autowired - public void setApplicationContext(ApplicationContext context) { - this.context = context; - } - - @Deprecated - public void setMessageExpessionHandler(List>> expressionHandlers) { - setMessageExpressionHandler(expressionHandlers); - } - - @Autowired(required = false) - public void setMessageExpressionHandler(List>> expressionHandlers) { - if (expressionHandlers.size() == 1) { - this.expressionHandler = expressionHandlers.get(0); - } - } - - @Autowired(required = false) - public void setObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - this.defaultExpressionHandler = objectPostProcessor.postProcess(this.defaultExpressionHandler); - } - - private SecurityExpressionHandler> getMessageExpressionHandler() { - if (this.expressionHandler == null) { - return this.defaultExpressionHandler; - } - return this.expressionHandler; - } - - @Override - public void afterSingletonsInstantiated() { - if (sameOriginDisabled()) { - return; - } - String beanName = "stompWebSocketHandlerMapping"; - SimpleUrlHandlerMapping mapping = this.context.getBean(beanName, SimpleUrlHandlerMapping.class); - Map mappings = mapping.getHandlerMap(); - for (Object object : mappings.values()) { - if (object instanceof SockJsHttpRequestHandler) { - setHandshakeInterceptors((SockJsHttpRequestHandler) object); - } - else if (object instanceof WebSocketHttpRequestHandler) { - setHandshakeInterceptors((WebSocketHttpRequestHandler) object); - } - else { - throw new IllegalStateException("Bean " + beanName + " is expected to contain mappings to either a " - + "SockJsHttpRequestHandler or a WebSocketHttpRequestHandler but got " + object); - } - } - if (this.inboundRegistry.containsMapping() && !this.inboundRegistry.isSimpDestPathMatcherConfigured()) { - PathMatcher pathMatcher = getDefaultPathMatcher(); - this.inboundRegistry.simpDestPathMatcher(pathMatcher); - } - } - - private void setHandshakeInterceptors(SockJsHttpRequestHandler handler) { - SockJsService sockJsService = handler.getSockJsService(); - Assert.state(sockJsService instanceof TransportHandlingSockJsService, - () -> "sockJsService must be instance of TransportHandlingSockJsService got " + sockJsService); - TransportHandlingSockJsService transportHandlingSockJsService = (TransportHandlingSockJsService) sockJsService; - List handshakeInterceptors = transportHandlingSockJsService.getHandshakeInterceptors(); - List interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1); - interceptorsToSet.add(new CsrfTokenHandshakeInterceptor()); - interceptorsToSet.addAll(handshakeInterceptors); - transportHandlingSockJsService.setHandshakeInterceptors(interceptorsToSet); - } - - private void setHandshakeInterceptors(WebSocketHttpRequestHandler handler) { - List handshakeInterceptors = handler.getHandshakeInterceptors(); - List interceptorsToSet = new ArrayList<>(handshakeInterceptors.size() + 1); - interceptorsToSet.add(new CsrfTokenHandshakeInterceptor()); - interceptorsToSet.addAll(handshakeInterceptors); - handler.setHandshakeInterceptors(interceptorsToSet); - } - - private static class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry { - - @Override - public MessageSecurityMetadataSource createMetadataSource() { - return super.createMetadataSource(); - } - - @Override - protected boolean containsMapping() { - return super.containsMapping(); - } - - @Override - protected boolean isSimpDestPathMatcherConfigured() { - return super.isSimpDestPathMatcherConfigured(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java deleted file mode 100644 index 6c3849d55f..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerDocTests.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.socket; - -import java.util.HashMap; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageDeliveryException; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.mock.web.MockServletConfig; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.security.web.csrf.DefaultCsrfToken; -import org.springframework.stereotype.Controller; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -public class AbstractSecurityWebSocketMessageBrokerConfigurerDocTests { - - AnnotationConfigWebApplicationContext context; - - TestingAuthenticationToken messageUser; - - CsrfToken token; - - String sessionAttr; - - @BeforeEach - public void setup() { - this.token = new DefaultCsrfToken("header", "param", "token"); - this.sessionAttr = "sessionAttr"; - this.messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER"); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void securityMappings() { - loadConfig(WebSocketSecurityConfig.class); - clientInboundChannel().send(message("/user/queue/errors", SimpMessageType.SUBSCRIBE)); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyAll", SimpMessageType.MESSAGE))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - private void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.register(WebSocketConfig.class, SyncExecutorConfig.class); - this.context.setServletConfig(new MockServletConfig()); - this.context.refresh(); - } - - private MessageChannel clientInboundChannel() { - return this.context.getBean("clientInboundChannel", MessageChannel.class); - } - - private Message message(String destination, SimpMessageType type) { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type); - return message(headers, destination); - } - - private Message message(SimpMessageHeaderAccessor headers, String destination) { - headers.setSessionId("123"); - headers.setSessionAttributes(new HashMap<>()); - if (destination != null) { - headers.setDestination(destination); - } - if (this.messageUser != null) { - headers.setUser(this.messageUser); - } - return new GenericMessage<>("hi", headers.getMessageHeaders()); - } - - @Controller - static class MyController { - - @MessageMapping("/authentication") - void authentication(@AuthenticationPrincipal String un) { - // ... do something ... - } - - } - - @Configuration - static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages.nullDestMatcher() - .authenticated() - // <1> - .simpSubscribeDestMatchers("/user/queue/errors") - .permitAll() - // <2> - .simpDestMatchers("/app/**") - .hasRole("USER") - // <3> - .simpSubscribeDestMatchers("/user/**", "/topic/friends/*") - .hasRole("USER") // <4> - .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE) - .denyAll() // <5> - .anyMessage() - .denyAll(); // <6> - } - - } - - @Configuration - @EnableWebSocketMessageBroker - static class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/chat").withSockJS(); - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - MyController myController() { - return new MyController(); - } - - } - - @Configuration - static class SyncExecutorConfig { - - @Bean - static SyncExecutorSubscribableChannelPostProcessor postProcessor() { - return new SyncExecutorSubscribableChannelPostProcessor(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java deleted file mode 100644 index 89af68e9da..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright 2002-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.socket; - -import java.util.HashMap; -import java.util.Map; - -import jakarta.servlet.http.HttpServletRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.MethodParameter; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageDeliveryException; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.messaging.support.AbstractMessageChannel; -import org.springframework.messaging.support.GenericMessage; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletConfig; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.access.expression.SecurityExpressionHandler; -import org.springframework.security.access.expression.SecurityExpressionOperations; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler; -import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot; -import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor; -import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource; -import org.springframework.security.messaging.context.SecurityContextChannelInterceptor; -import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.security.web.csrf.DefaultCsrfToken; -import org.springframework.security.web.csrf.DeferredCsrfToken; -import org.springframework.security.web.csrf.MissingCsrfTokenException; -import org.springframework.stereotype.Controller; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.util.AntPathMatcher; -import org.springframework.web.HttpRequestHandler; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.server.HandshakeFailureException; -import org.springframework.web.socket.server.HandshakeHandler; -import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; -import org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler; -import org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.security.web.csrf.CsrfTokenAssert.assertThatCsrfToken; - -public class AbstractSecurityWebSocketMessageBrokerConfigurerTests { - - AnnotationConfigWebApplicationContext context; - - TestingAuthenticationToken messageUser; - - CsrfToken token; - - String sessionAttr; - - @BeforeEach - public void setup() { - this.token = new DefaultCsrfToken("header", "param", "token"); - this.sessionAttr = "sessionAttr"; - this.messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER"); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void simpleRegistryMappings() { - loadConfig(SockJsSecurityConfig.class); - clientInboundChannel().send(message("/permitAll")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyAll"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void annonymousSupported() { - loadConfig(SockJsSecurityConfig.class); - this.messageUser = null; - clientInboundChannel().send(message("/permitAll")); - } - - // gh-3797 - @Test - public void beanResolver() { - loadConfig(SockJsSecurityConfig.class); - this.messageUser = null; - clientInboundChannel().send(message("/beanResolver")); - } - - @Test - public void addsAuthenticationPrincipalResolver() { - loadConfig(SockJsSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Message message = message("/permitAll/authentication"); - messageChannel.send(message); - assertThat(this.context.getBean(MyController.class).authenticationPrincipal) - .isEqualTo((String) this.messageUser.getPrincipal()); - } - - @Test - public void addsAuthenticationPrincipalResolverWhenNoAuthorization() { - loadConfig(NoInboundSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - Message message = message("/permitAll/authentication"); - messageChannel.send(message); - assertThat(this.context.getBean(MyController.class).authenticationPrincipal) - .isEqualTo((String) this.messageUser.getPrincipal()); - } - - @Test - public void addsCsrfProtectionWhenNoAuthorization() { - loadConfig(NoInboundSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MessageChannel messageChannel = clientInboundChannel(); - assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() -> messageChannel.send(message)) - .withCauseInstanceOf(MissingCsrfTokenException.class); - } - - @Test - public void csrfProtectionForConnect() { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MessageChannel messageChannel = clientInboundChannel(); - assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() -> messageChannel.send(message)) - .withCauseInstanceOf(MissingCsrfTokenException.class); - } - - @Test - public void csrfProtectionDisabledForConnect() { - loadConfig(CsrfDisabledSockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/permitAll/connect"); - MessageChannel messageChannel = clientInboundChannel(); - messageChannel.send(message); - } - - @Test - public void csrfProtectionDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - CsrfChannelInterceptor csrfChannelInterceptor = this.context.getBean(CsrfChannelInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(csrfChannelInterceptor); - } - - @Test - public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = sockjsHttpRequest("/chat"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void messagesConnectUseCsrfTokenHandshakeInterceptorMultipleMappings() throws Exception { - loadConfig(SockJsSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = sockjsHttpRequest("/other"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void messagesConnectWebSocketUseCsrfTokenHandshakeInterceptor() throws Exception { - loadConfig(WebSocketSecurityConfig.class); - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); - Message message = message(headers, "/authentication"); - MockHttpServletRequest request = websocketHttpRequest("/websocket"); - HttpRequestHandler handler = handler(request); - handler.handleRequest(request, new MockHttpServletResponse()); - assertHandshake(request); - } - - @Test - public void msmsRegistryCustomPatternMatcher() { - loadConfig(MsmsRegistryCustomPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a.b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a.b.c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void overrideMsmsRegistryCustomPatternMatcher() { - loadConfig(OverrideMsmsRegistryCustomPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a/b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a/b/c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void defaultPatternMatcher() { - loadConfig(DefaultPatternMatcherConfig.class); - clientInboundChannel().send(message("/app/a/b")); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/app/a/b/c"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void customExpression() { - loadConfig(CustomExpressionConfig.class); - clientInboundChannel().send(message("/denyRob")); - this.messageUser = new TestingAuthenticationToken("rob", "password", "ROLE_USER"); - assertThatExceptionOfType(MessageDeliveryException.class) - .isThrownBy(() -> clientInboundChannel().send(message("/denyRob"))) - .withCauseInstanceOf(AccessDeniedException.class); - } - - @Test - public void channelSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() { - loadConfig(SockJsProxylessSecurityConfig.class); - ChannelSecurityInterceptor channelSecurityInterceptor = this.context.getBean(ChannelSecurityInterceptor.class); - MessageSecurityMetadataSource messageSecurityMetadataSource = this.context - .getBean(MessageSecurityMetadataSource.class); - assertThat(channelSecurityInterceptor.obtainSecurityMetadataSource()).isSameAs(messageSecurityMetadataSource); - } - - @Test - public void securityContextChannelInterceptorDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - SecurityContextChannelInterceptor securityContextChannelInterceptor = this.context - .getBean(SecurityContextChannelInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()) - .contains(securityContextChannelInterceptor); - } - - @Test - public void inboundChannelSecurityDefinedByBean() { - loadConfig(SockJsProxylessSecurityConfig.class); - MessageChannel messageChannel = clientInboundChannel(); - ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class); - assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(inboundChannelSecurity); - } - - private void assertHandshake(HttpServletRequest request) { - TestHandshakeHandler handshakeHandler = this.context.getBean(TestHandshakeHandler.class); - assertThatCsrfToken(handshakeHandler.attributes.get(CsrfToken.class.getName())).isEqualTo(this.token); - assertThat(handshakeHandler.attributes).containsEntry(this.sessionAttr, - request.getSession().getAttribute(this.sessionAttr)); - } - - private HttpRequestHandler handler(HttpServletRequest request) throws Exception { - HandlerMapping handlerMapping = this.context.getBean(HandlerMapping.class); - return (HttpRequestHandler) handlerMapping.getHandler(request).getHandler(); - } - - private MockHttpServletRequest websocketHttpRequest(String mapping) { - MockHttpServletRequest request = sockjsHttpRequest(mapping); - request.setRequestURI(mapping); - return request; - } - - private MockHttpServletRequest sockjsHttpRequest(String mapping) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); - request.setMethod("GET"); - request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/289/tpyx6mde/websocket"); - request.setRequestURI(mapping + "/289/tpyx6mde/websocket"); - request.getSession().setAttribute(this.sessionAttr, "sessionValue"); - request.setAttribute(DeferredCsrfToken.class.getName(), new TestDeferredCsrfToken(this.token)); - return request; - } - - private Message message(String destination) { - SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); - return message(headers, destination); - } - - private Message message(SimpMessageHeaderAccessor headers, String destination) { - headers.setSessionId("123"); - headers.setSessionAttributes(new HashMap<>()); - if (destination != null) { - headers.setDestination(destination); - } - if (this.messageUser != null) { - headers.setUser(this.messageUser); - } - return new GenericMessage<>("hi", headers.getMessageHeaders()); - } - - private MessageChannel clientInboundChannel() { - return this.context.getBean("clientInboundChannel", MessageChannel.class); - } - - private void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.setServletConfig(new MockServletConfig()); - this.context.refresh(); - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class MsmsRegistryCustomPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/app/a.*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class OverrideMsmsRegistryCustomPatternMatcherConfig - extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestPathMatcher(new AntPathMatcher()) - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setPathMatcher(new AntPathMatcher(".")); - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class DefaultPatternMatcherConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/app/a/*").permitAll() - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class CustomExpressionConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry - .addEndpoint("/other") - .setHandshakeHandler(testHandshakeHandler()); - } - // @formatter:on - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .anyMessage().access("denyRob()"); - } - // @formatter:on - @Bean - static SecurityExpressionHandler> messageSecurityExpressionHandler() { - return new DefaultMessageSecurityExpressionHandler() { - @Override - protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, - Message invocation) { - return new MessageSecurityExpressionRoot(authentication, invocation) { - public boolean denyRob() { - Authentication auth = getAuthentication(); - return auth != null && !"rob".equals(auth.getName()); - } - }; - } - }; - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Controller - static class MyController { - - String authenticationPrincipal; - - MyCustomArgument myCustomArgument; - - @MessageMapping("/authentication") - public void authentication(@AuthenticationPrincipal String un) { - this.authenticationPrincipal = un; - } - - @MessageMapping("/myCustom") - public void myCustom(MyCustomArgument myCustomArgument) { - this.myCustomArgument = myCustomArgument; - } - - } - - static class MyCustomArgument { - - MyCustomArgument(String notDefaultConstr) { - } - - } - - static class MyCustomArgumentResolver implements HandlerMethodArgumentResolver { - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return parameter.getParameterType().isAssignableFrom(MyCustomArgument.class); - } - - @Override - public Object resolveArgument(MethodParameter parameter, Message message) { - return new MyCustomArgument(""); - } - - } - - static class TestHandshakeHandler implements HandshakeHandler { - - Map attributes; - - @Override - public boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, - Map attributes) throws HandshakeFailureException { - this.attributes = attributes; - if (wsHandler instanceof SockJsWebSocketHandler) { - // work around SPR-12716 - SockJsWebSocketHandler sockJs = (SockJsWebSocketHandler) wsHandler; - WebSocketServerSockJsSession session = (WebSocketServerSockJsSession) ReflectionTestUtils - .getField(sockJs, "sockJsSession"); - this.attributes = session.getAttributes(); - } - return true; - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/other").setHandshakeHandler(testHandshakeHandler()) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - registry.addEndpoint("/chat").setHandshakeHandler(testHandshakeHandler()) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/permitAll/**").permitAll() - .simpDestMatchers("/beanResolver/**").access("@security.check()") - .anyMessage().denyAll(); - } - // @formatter:on - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - public MyController myController() { - return new MyController(); - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - @Bean - public SecurityCheck security() { - return new SecurityCheck(); - } - - static class SecurityCheck { - - private boolean check; - - public boolean check() { - this.check = !this.check; - return this.check; - } - - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class NoInboundSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/other") - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - registry.addEndpoint("/chat") - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll"); - } - - @Bean - public MyController myController() { - return new MyController(); - } - - } - - @Configuration - static class CsrfDisabledSockJsSecurityConfig extends SockJsSecurityConfig { - - @Override - protected boolean sameOriginDisabled() { - return true; - } - - } - - @Configuration - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/websocket") - .setHandshakeHandler(testHandshakeHandler()) - .addInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - // @formatter:off - messages - .simpDestMatchers("/permitAll/**").permitAll() - .simpDestMatchers("/customExpression/**").access("denyRob") - .anyMessage().denyAll(); - // @formatter:on - } - - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class SockJsProxylessSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - private ApplicationContext context; - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/chat") - .setHandshakeHandler(this.context.getBean(TestHandshakeHandler.class)) - .withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .anyMessage().denyAll(); - } - // @formatter:on - @Bean - public TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - - @Configuration - static class SyncExecutorConfig { - - @Bean - public static SyncExecutorSubscribableChannelPostProcessor postProcessor() { - return new SyncExecutorSubscribableChannelPostProcessor(); - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java index cf2d035806..7e7c442080 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/socket/WebSocketMessageBrokerSecurityConfigurationTests.java @@ -69,7 +69,6 @@ import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; import org.springframework.security.config.observation.SecurityObservationSettings; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; @@ -878,37 +877,6 @@ public class WebSocketMessageBrokerSecurityConfigurationTests { } - @Configuration - @EnableWebSocketSecurity - @EnableWebSocketMessageBroker - @Import(SyncExecutorConfig.class) - static class UsingLegacyConfigurerConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - // @formatter:off - registry.addEndpoint("/websocket") - .setHandshakeHandler(testHandshakeHandler()) - .addInterceptors(new HttpSessionHandshakeInterceptor()); - // @formatter:on - } - - @Override - public void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - // @formatter:off - messages - .simpDestMatchers("/permitAll/**").permitAll() - .anyMessage().denyAll(); - // @formatter:on - } - - @Bean - TestHandshakeHandler testHandshakeHandler() { - return new TestHandshakeHandler(); - } - - } - @Configuration(proxyBeanMethods = false) @EnableWebSocketSecurity @EnableWebSocketMessageBroker diff --git a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc index 736e5b15f4..a4827bac7b 100644 --- a/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc +++ b/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc @@ -492,43 +492,6 @@ Xml:: ---- ====== -On the other hand, if you are using the <> and you want to allow other domains to access your site, you can disable Spring Security's protection. -For example, in Java Configuration you can use the following: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - ... - - @Override - protected boolean sameOriginDisabled() { - return true; - } -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() { - - // ... - - override fun sameOriginDisabled(): Boolean { - return true - } -} ----- -====== - [[websocket-expression-handler]] === Custom Expression Handler @@ -742,50 +705,3 @@ If we use XML-based configuration, we can use thexref:servlet/appendix/namespace ---- - -[[legacy-websocket-configuration]] -== Legacy WebSocket Configuration - -Before Spring Security 5.8, the way to configure messaging authorization using Java Configuration, was to extend the `AbstractSecurityWebSocketMessageBrokerConfigurer` and configure the `MessageSecurityMetadataSourceRegistry`. -For example: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@Configuration -public class WebSocketSecurityConfig - extends AbstractSecurityWebSocketMessageBrokerConfigurer { // <1> <2> - - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpDestMatchers("/user/**").authenticated() // <3> - } -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@Configuration -open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() { // <1> <2> - override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) { - messages.simpDestMatchers("/user/**").authenticated() // <3> - } -} ----- -====== - -This will ensure that: - -<1> Any inbound CONNECT message requires a valid CSRF token to enforce <> -<2> The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request. -<3> Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <> - -Using the legacy configuration is helpful in the event that you have a custom `SecurityExpressionHandler` that extends `AbstractSecurityExpressionHandler` and overrides `createEvaluationContextInternal` or `createSecurityExpressionRoot`. -In order to defer `Authorization` lookup, the new `AuthorizationManager` API does not invoke these when evaluating expressions. - -If you are using XML, you can use the legacy APIs simply by not using the `use-authorization-manager` element or setting it to `false`. diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml index c1c5baf08a..6bc4e30592 100644 --- a/etc/checkstyle/checkstyle-suppressions.xml +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -17,7 +17,6 @@ - From bfecd2583dbe2d132fd2507b76bc0ccc7bebbfec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:19 +0000 Subject: [PATCH 442/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..7197d56f69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From 3537b5c313ad476cdd5bfef02d349b286e436882 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:31 +0000 Subject: [PATCH 443/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From d06f73cde92e8ee6915470a6fdf85174617a9727 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:36 +0000 Subject: [PATCH 444/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From b1909a0b251993d24e20c2486f5a1b6172ffe54d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:49 +0000 Subject: [PATCH 445/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From c2bea7ef9a64e324fa0f3f83152f7f50ef85ac41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:50 +0000 Subject: [PATCH 446/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 90672c54e7676c3709d59e8855f9d135fef2d3f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:36:57 +0000 Subject: [PATCH 447/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..c465d30087 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 784583c216bf418f86aa1adb89676be07df25d32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:37:00 +0000 Subject: [PATCH 448/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 8e609e5d64000da2573e7144e0a210c22d3fa583 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:37:15 +0000 Subject: [PATCH 449/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 9e58f2fcfe13e0d1a0351933e7059eb5c2e3052c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 03:37:32 +0000 Subject: [PATCH 450/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..0475e149f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 6dcfd3c6b2f23ba327b4330450924fba826e5688 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:01:00 +0000 Subject: [PATCH 451/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From f9c042595437fe5a7ba6d670b5873b6760cf10da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:01:06 +0000 Subject: [PATCH 452/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a12ae45547 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 953dbc6858569f8b25287647b85fe324fbeb2179 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:01:30 +0000 Subject: [PATCH 453/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..760e98560c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 581906c23fdfc0d88aa168dd6d2b56f07883dafa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:01:36 +0000 Subject: [PATCH 454/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.18.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.18.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.18/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.17...6.6.18) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.18.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..98c4e279d0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.18.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From ce8be6d5238d49c7c2302ee169b879a69b0272ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 04:01:46 +0000 Subject: [PATCH 455/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 00ead7f24dcd55538a565b827c981705453ba72a Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:25:49 -0500 Subject: [PATCH 456/504] Update to Kotlin 2.2 --- buildSrc/build.gradle | 2 ++ buildSrc/src/main/groovy/security-kotlin.gradle | 17 +++++++++++++++++ config/spring-security-config.gradle | 11 +---------- .../config/web/server/ServerX509DslTests.kt | 2 +- core/spring-security-core.gradle | 13 +------------ docs/spring-security-docs.gradle | 13 +------------ ...ientHttpInterfaceIntegrationConfiguration.kt | 6 +++--- .../reactivex509/X509ConfigurationTests.kt | 8 +++++--- gradle/libs.versions.toml | 4 ++-- 9 files changed, 33 insertions(+), 43 deletions(-) create mode 100644 buildSrc/src/main/groovy/security-kotlin.gradle diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 48483f7438..04eef4fedf 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,5 +1,6 @@ plugins { id "java-gradle-plugin" + id "groovy-gradle-plugin" id "java" id "groovy" } @@ -76,6 +77,7 @@ dependencies { implementation libs.com.github.spullara.mustache.java.compiler implementation libs.io.spring.javaformat.spring.javaformat.gradle.plugin implementation libs.io.spring.nohttp.nohttp.gradle + implementation libs.org.jetbrains.kotlin.kotlin.gradle.plugin implementation (libs.net.sourceforge.htmlunit) { exclude group: 'org.eclipse.jetty.websocket', module: 'websocket-client' } diff --git a/buildSrc/src/main/groovy/security-kotlin.gradle b/buildSrc/src/main/groovy/security-kotlin.gradle new file mode 100644 index 0000000000..5b1f3e199a --- /dev/null +++ b/buildSrc/src/main/groovy/security-kotlin.gradle @@ -0,0 +1,17 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id 'kotlin' +} + +project.plugins.withId("org.jetbrains.kotlin.jvm", (kotlinProject) -> { + project.tasks.withType(KotlinCompile).configureEach { + kotlinOptions { + languageVersion = '2.2' + apiVersion = '2.2' + freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"] + jvmTarget = '17' + + } + } +}) diff --git a/config/spring-security-config.gradle b/config/spring-security-config.gradle index 322f77af47..6eeda65d66 100644 --- a/config/spring-security-config.gradle +++ b/config/spring-security-config.gradle @@ -4,7 +4,7 @@ import trang.RncToXsd apply plugin: 'io.spring.convention.spring-module' apply plugin: 'trang' -apply plugin: 'kotlin' +apply plugin: 'security-kotlin' configurations { opensaml5 { @@ -153,15 +153,6 @@ tasks.named('sourcesJar', Jar).configure { } } -tasks.withType(KotlinCompile).configureEach { - kotlinOptions { - languageVersion = "1.7" - apiVersion = "1.7" - freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"] - jvmTarget = "17" - } -} - configure(project.tasks.withType(Test)) { doFirst { systemProperties['springSecurityVersion'] = version diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerX509DslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerX509DslTests.kt index 8685fc22fe..e82ec296e6 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerX509DslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerX509DslTests.kt @@ -205,7 +205,7 @@ class ServerX509DslTests { @Nullable httpHandlerBuilder: WebHttpHandlerBuilder?, @Nullable connector: ClientHttpConnector?) { val filter = SetSslInfoWebFilter(certificate) - httpHandlerBuilder!!.filters { filters: MutableList -> filters.add(0, filter) } + httpHandlerBuilder!!.filters { filters: MutableList -> filters.add(0, filter) } } } diff --git a/core/spring-security-core.gradle b/core/spring-security-core.gradle index 358ad5775b..a81cc81d60 100644 --- a/core/spring-security-core.gradle +++ b/core/spring-security-core.gradle @@ -1,9 +1,7 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - import java.util.concurrent.Callable apply plugin: 'io.spring.convention.spring-module' -apply plugin: 'kotlin' +apply plugin: 'security-kotlin' dependencies { management platform(project(":spring-security-dependencies")) @@ -66,12 +64,3 @@ Callable springVersion() { return (Callable) { project.configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts .find { it.name == 'spring-core' }.moduleVersion.id.version } } - -tasks.withType(KotlinCompile).configureEach { - kotlinOptions { - languageVersion = "1.7" - apiVersion = "1.7" - freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"] - jvmTarget = "17" - } -} diff --git a/docs/spring-security-docs.gradle b/docs/spring-security-docs.gradle index 23e8d0db91..75ed6b018a 100644 --- a/docs/spring-security-docs.gradle +++ b/docs/spring-security-docs.gradle @@ -1,10 +1,8 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { id 'org.antora' version '1.0.0' id 'io.spring.antora.generate-antora-yml' version '0.0.1' id 'io.spring.convention.repository' - id 'kotlin' + id 'security-kotlin' } apply plugin: 'io.spring.convention.docs' @@ -100,12 +98,3 @@ def resolvedVersions(Configuration configuration) { test { useJUnitPlatform() } - -tasks.withType(KotlinCompile).configureEach { - kotlinOptions { - languageVersion = "1.7" - apiVersion = "1.7" - freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"] - jvmTarget = "17" - } -} diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt index 89fa67348e..dd9472dab5 100644 --- a/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/features/integrations/rest/configurationwebclient/ServerWebClientHttpInterfaceIntegrationConfiguration.kt @@ -54,11 +54,11 @@ class ServerWebClientHttpInterfaceIntegrationConfiguration { @Bean fun groupConfigurer(server: MockWebServer): WebClientHttpServiceGroupConfigurer { - return WebClientHttpServiceGroupConfigurer { groups: HttpServiceGroupConfigurer.Groups? -> + return WebClientHttpServiceGroupConfigurer { groups: HttpServiceGroupConfigurer.Groups -> val baseUrl = server.url("").toString() groups!! - .forEachClient(ClientCallback { group: HttpServiceGroup?, builder: WebClient.Builder? -> - builder!! + .forEachClient(ClientCallback { group: HttpServiceGroup, builder: WebClient.Builder -> + builder .baseUrl(baseUrl) .defaultHeader("Accept", "application/vnd.github.v3+json") }) diff --git a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt index 4802660f06..3c8f779f2f 100644 --- a/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt +++ b/docs/src/test/kotlin/org/springframework/security/kt/docs/reactive/authentication/reactivex509/X509ConfigurationTests.kt @@ -28,6 +28,7 @@ import org.springframework.security.test.web.reactive.server.WebTestClientBuilde import org.springframework.security.web.authentication.preauth.x509.X509TestUtils import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.test.web.reactive.server.WebTestClientConfigurer +import org.springframework.util.Assert import org.springframework.web.server.ServerWebExchange import org.springframework.web.server.WebFilter import org.springframework.web.server.WebFilterChain @@ -108,18 +109,19 @@ class X509ConfigurationTests { companion object { private fun x509(certificate: X509Certificate): WebTestClientConfigurer { - return WebTestClientConfigurer { builder: WebTestClient.Builder, httpHandlerBuilder: WebHttpHandlerBuilder, connector: ClientHttpConnector? -> + return WebTestClientConfigurer { builder: WebTestClient.Builder, httpHandlerBuilder: WebHttpHandlerBuilder?, connector: ClientHttpConnector? -> val sslInfo: SslInfo = object : SslInfo { override fun getSessionId(): String { return "sessionId" } - override fun getPeerCertificates(): Array { + override fun getPeerCertificates(): Array { return arrayOf(certificate) } } - httpHandlerBuilder.filters(Consumer { filters: MutableList -> + Assert.notNull(httpHandlerBuilder, "httpHandlerBuilder should not be null") + httpHandlerBuilder!!.filters(Consumer { filters: MutableList -> filters.add( 0, SslInfoOverrideWebFilter(sslInfo) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd27bc3f4..ea4397a39b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ org-apache-maven-resolver = "1.9.23" org-aspectj = "1.9.24" org-bouncycastle = "1.80" org-eclipse-jetty = "11.0.25" -org-jetbrains-kotlin = "1.9.25" +org-jetbrains-kotlin = "2.2.0" org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" @@ -67,7 +67,7 @@ org-hamcrest = "org.hamcrest:hamcrest:2.2" org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } -org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" +org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0" org-jetbrains-kotlinx-kotlinx-coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "org-jetbrains-kotlinx" } org-junit-junit-bom = "org.junit:junit-bom:5.12.2" org-mockito-mockito-bom = { module = "org.mockito:mockito-bom", version.ref = "org-mockito" } From 123ba5a81ae4ca9db99cff55f5385402c0b230a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 22:33:45 +0000 Subject: [PATCH 457/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.3.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.3.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.3/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.3) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.3.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..dac4f072f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.3.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0" From 586340b2ae0b8c9c5fb986ad3e46a9f1fd3104d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:34:29 +0000 Subject: [PATCH 458/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..937f843bcf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 5dce2ab50053f40d6909eb2444a86bacb28c4e19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:35:01 +0000 Subject: [PATCH 459/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..edb76aeb40 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-maven-resolver = "1.9.23" From feffe23a0e431dae8cc994c7bb940d0e4af8428b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:35:12 +0000 Subject: [PATCH 460/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..89b3f104a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 4e6e25d3a5fd66bd33847eb9bc3954601d1abb0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:35:27 +0000 Subject: [PATCH 461/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..7ec855332a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From e4a2ac27d6b96eade5fbe941ae5525d815aea362 Mon Sep 17 00:00:00 2001 From: Konstantin Filtschew Date: Fri, 20 Jun 2025 14:37:12 +0200 Subject: [PATCH 462/504] Fixed link to CSRF checks --- docs/modules/ROOT/pages/features/exploits/csrf.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/features/exploits/csrf.adoc b/docs/modules/ROOT/pages/features/exploits/csrf.adoc index 28a1903e5f..34184006af 100644 --- a/docs/modules/ROOT/pages/features/exploits/csrf.adoc +++ b/docs/modules/ROOT/pages/features/exploits/csrf.adoc @@ -324,7 +324,7 @@ This lets the expected CSRF token outlive the session. + One might ask why the expected CSRF token is not stored in a cookie by default. This is because there are known exploits in which headers (for example, to specify the cookies) can be set by another domain. -This is the same reason Ruby on Rails https://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/[no longer skips a CSRF checks when the header X-Requested-With is present]. +This is the same reason Ruby on Rails https://rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails[no longer skips a CSRF checks when the header X-Requested-With is present]. See https://web.archive.org/web/20210221120355/https://lists.webappsec.org/pipermail/websecurity_lists.webappsec.org/2011-February/007533.html[this webappsec.org thread] for details on how to perform the exploit. Another disadvantage is that by removing the state (that is, the timeout), you lose the ability to forcibly invalidate the token if it is compromised. From 2f53a2edb34b690ba2f533732d62f7a58a55d577 Mon Sep 17 00:00:00 2001 From: Soumik Sarker Date: Thu, 19 Jun 2025 23:49:47 +0600 Subject: [PATCH 463/504] Removed deprecated Base64 of crypto package Signed-off-by: Soumik Sarker --- .../security/crypto/codec/Base64.java | 629 ------------------ .../security/crypto/codec/Base64Tests.java | 52 -- 2 files changed, 681 deletions(-) delete mode 100644 crypto/src/main/java/org/springframework/security/crypto/codec/Base64.java delete mode 100644 crypto/src/test/java/org/springframework/security/crypto/codec/Base64Tests.java diff --git a/crypto/src/main/java/org/springframework/security/crypto/codec/Base64.java b/crypto/src/main/java/org/springframework/security/crypto/codec/Base64.java deleted file mode 100644 index b696c0c4bf..0000000000 --- a/crypto/src/main/java/org/springframework/security/crypto/codec/Base64.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.crypto.codec; - -/** - * Base64 encoder which is a reduced version of Robert Harder's public domain - * implementation (version 2.3.7). See http://iharder.sourceforge.net/current/java/base64/ - * for more information. - *

- * For internal use only. - * - * @author Luke Taylor - * @since 3.0 - * @deprecated Use java.util.Base64 - */ -@Deprecated -public final class Base64 { - - /** No options specified. Value is zero. */ - public static final int NO_OPTIONS = 0; - - /** Specify encoding in first bit. Value is one. */ - public static final int ENCODE = 1; - - /** Specify decoding in first bit. Value is zero. */ - public static final int DECODE = 0; - - /** Do break lines when encoding. Value is 8. */ - public static final int DO_BREAK_LINES = 8; - - /** - * Encode using Base64-like encoding that is URL- and Filename-safe as described in - * Section 4 of RFC3548: https://tools.ietf.org/html/rfc3548. It - * is important to note that data encoded this way is not officially valid - * Base64, or at the very least should not be called Base64 without also specifying - * that is was encoded using the URL- and Filename-safe dialect. - */ - public static final int URL_SAFE = 16; - - /** - * Encode using the special "ordered" dialect of Base64. - */ - public static final int ORDERED = 32; - - /** Maximum line length (76) of Base64 output. */ - private static final int MAX_LINE_LENGTH = 76; - - /** The equals sign (=) as a byte. */ - private static final byte EQUALS_SIGN = (byte) '='; - - /** The new line character (\n) as a byte. */ - private static final byte NEW_LINE = (byte) '\n'; - - private static final byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding - - private static final byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding - - /* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ - - /** The 64 valid Base64 values. */ - /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ - private static final byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', - (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', - (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', - (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', - (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', - (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', - (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' }; - - /** - * Translates a Base64 value to either its 6-bit reconstruction value or a negative - * number indicating some other meaning. - **/ - private static final byte[] _STANDARD_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal - // 0 - // - - // 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9, // Decimal 123 - 127 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - /* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ - - /** - * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: - * https://tools.ietf.org/html/rfc3548. - * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" - * and "slash." - */ - private static final byte[] _URL_SAFE_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', - (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', - (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', - (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', - (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', - (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', - (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' }; - - /** - * Used in decoding URL- and Filename-safe dialects of Base64. - */ - private static final byte[] _URL_SAFE_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal - // 0 - // - - // 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 62, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, // Decimal 91 - 94 - 63, // Underscore at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9, // Decimal 123 - 127 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - /* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ - - private static final byte[] _ORDERED_ALPHABET = { (byte) '-', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C', - (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', - (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c', - (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', - (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', - (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z' }; - - /** - * Used in decoding the "ordered" dialect of Base64. - */ - private static final byte[] _ORDERED_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, - // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - -9, // Plus sign at decimal 43 - -9, // Decimal 44 - 0, // Minus sign at decimal 45 - -9, // Decimal 46 - -9, // Slash at decimal 47 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M' - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z' - -9, -9, -9, -9, // Decimal 91 - 94 - 37, // Underscore at decimal 95 - -9, // Decimal 96 - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm' - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z' - -9, -9, -9, -9, -9, // Decimal 123 - 127 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243 - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255 - }; - - private Base64() { - } - - public static byte[] decode(byte[] bytes) { - return decode(bytes, 0, bytes.length, NO_OPTIONS); - } - - public static byte[] encode(byte[] bytes) { - return encodeBytesToBytes(bytes, 0, bytes.length, NO_OPTIONS); - } - - public static boolean isBase64(byte[] bytes) { - try { - decode(bytes); - } - catch (InvalidBase64CharacterException ex) { - return false; - } - return true; - } - - /** - * Returns one of the _SOMETHING_ALPHABET byte arrays depending on the options - * specified. It's possible, though silly, to specify ORDERED and URLSAFE in - * which case one of them will be picked, though there is no guarantee as to which one - * will be picked. - */ - private static byte[] getAlphabet(int options) { - if ((options & URL_SAFE) == URL_SAFE) { - return _URL_SAFE_ALPHABET; - } - else if ((options & ORDERED) == ORDERED) { - return _ORDERED_ALPHABET; - } - else { - return _STANDARD_ALPHABET; - } - } - - /** - * Returns one of the _SOMETHING_DECODABET byte arrays depending on the options - * specified. It's possible, though silly, to specify ORDERED and URL_SAFE in which - * case one of them will be picked, though there is no guarantee as to which one will - * be picked. - */ - private static byte[] getDecodabet(int options) { - if ((options & URL_SAFE) == URL_SAFE) { - return _URL_SAFE_DECODABET; - } - else if ((options & ORDERED) == ORDERED) { - return _ORDERED_DECODABET; - } - else { - return _STANDARD_DECODABET; - } - } - - /* ******** E N C O D I N G M E T H O D S ******** */ - - /** - *

- * Encodes up to three bytes of the array source and writes the resulting - * four Base64 bytes to destination. The source and destination arrays can - * be manipulated anywhere along their length by specifying srcOffset and - * destOffset. This method does not check to make sure your arrays are - * large enough to accomodate srcOffset + 3 for the source array - * or destOffset + 4 for the destination array. The actual - * number of significant bytes in your array is given by numSigBytes. - *

- *

- * This is the lowest level of the encoding methods with all possible parameters. - *

- * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param numSigBytes the number of significant bytes in your array - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset, - int options) { - - byte[] ALPHABET = getAlphabet(options); - - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index ALPHABET - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3f 0x3f 0x3f Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an int. - int inBuff = ((numSigBytes > 0) ? ((source[srcOffset] << 24) >>> 8) : 0) - | ((numSigBytes > 1) ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | ((numSigBytes > 2) ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - - switch (numSigBytes) { - case 3: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; - return destination; - - case 2: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - - case 1: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = EQUALS_SIGN; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - - default: - return destination; - } - } - - /** - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @param options Specified options - * @return The Base64-encoded data as a String - * @throws java.io.IOException if there is an error - * @throws NullPointerException if source array is null - * @throws IllegalArgumentException if source array, offset, or length are invalid - * @since 2.3.1 - * @see Base64#DO_BREAK_LINES - */ - private static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) { - - if (source == null) { - throw new NullPointerException("Cannot serialize a null array."); - } // end if: null - - if (off < 0) { - throw new IllegalArgumentException("Cannot have negative offset: " + off); - } // end if: off < 0 - - if (len < 0) { - throw new IllegalArgumentException("Cannot have length offset: " + len); - } // end if: len < 0 - - if (off + len > source.length) { - throw new IllegalArgumentException(String - .format("Cannot have offset of %d and length of %d with array of length %d", off, len, source.length)); - } // end if: off < 0 - - boolean breakLines = (options & DO_BREAK_LINES) > 0; - - // int len43 = len * 4 / 3; - // byte[] outBuff = new byte[ ( len43 ) // Main 4:3 - // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding - // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines - // Try to determine more precisely how big the array needs to be. - // If we get it right, we don't have to do an array copy, and - // we save a bunch of memory. - - // Bytes needed for actual encoding - int encLen = (len / 3) * 4 + ((len % 3 > 0) ? 4 : 0); - - if (breakLines) { - encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters - } - byte[] outBuff = new byte[encLen]; - - int d = 0; - int e = 0; - int len2 = len - 2; - int lineLength = 0; - for (; d < len2; d += 3, e += 4) { - encode3to4(source, d + off, 3, outBuff, e, options); - - lineLength += 4; - if (breakLines && lineLength >= MAX_LINE_LENGTH) { - outBuff[e + 4] = NEW_LINE; - e++; - lineLength = 0; - } // end if: end of line - } // en dfor: each piece of array - - if (d < len) { - encode3to4(source, d + off, len - d, outBuff, e, options); - e += 4; - } // end if: some padding needed - - // Only resize array if we didn't guess it right. - if (e <= outBuff.length - 1) { - byte[] finalOut = new byte[e]; - System.arraycopy(outBuff, 0, finalOut, 0, e); - // System.err.println("Having to resize array from " + outBuff.length + " to " - // + e ); - return finalOut; - } - else { - // System.err.println("No need to resize array."); - return outBuff; - } - } - - /* ******** D E C O D I N G M E T H O D S ******** */ - - /** - * Decodes four bytes from array source and writes the resulting bytes (up - * to three of them) to destination. The source and destination arrays can - * be manipulated anywhere along their length by specifying srcOffset and - * destOffset. This method does not check to make sure your arrays are - * large enough to accomodate srcOffset + 4 for the source array - * or destOffset + 3 for the destination array. This method - * returns the actual number of bytes that were converted from the Base64 encoding. - *

- * This is the lowest level of the decoding methods with all possible parameters. - *

- * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param options alphabet type is pulled from this (standard, url-safe, ordered) - * @return the number of decoded bytes converted - * @throws NullPointerException if source or destination arrays are null - * @throws IllegalArgumentException if srcOffset or destOffset are invalid or there is - * not enough room in the array. - * @since 1.3 - */ - private static int decode4to3(final byte[] source, final int srcOffset, final byte[] destination, - final int destOffset, final int options) { - - // Lots of error checking and exception throwing - if (source == null) { - throw new NullPointerException("Source array was null."); - } // end if - if (destination == null) { - throw new NullPointerException("Destination array was null."); - } // end if - if (srcOffset < 0 || srcOffset + 3 >= source.length) { - throw new IllegalArgumentException( - String.format("Source array with length %d cannot have offset of %d and still process four bytes.", - source.length, srcOffset)); - } // end if - if (destOffset < 0 || destOffset + 2 >= destination.length) { - throw new IllegalArgumentException(String.format( - "Destination array with length %d cannot have offset of %d and still store three bytes.", - destination.length, destOffset)); - } // end if - - byte[] DECODABET = getDecodabet(options); - - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } - - // Example: DkL= - else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Two ways to do the same thing. Don't know which way I like best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } - - // Example: DkLE - else { - // Two ways to do the same thing. Don't know which way I like best. - // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) - // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) - // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) - // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); - int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) - | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) - | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF)); - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - - return 3; - } - } - - /** - * Low-level access to decoding ASCII characters in the form of a byte array. - * Ignores GUNZIP option, if it's set. This is not generally a - * recommended method, although it is used internally as part of the decoding process. - * Special case: if len = 0, an empty array is returned. Still, if you need more speed - * and reduced memory footprint (and aren't gzipping), consider this method. - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @param options Can specify options such as alphabet type to use - * @return decoded data - * @throws IllegalArgumentException If bogus characters exist in source data - */ - private static byte[] decode(final byte[] source, final int off, final int len, final int options) { - - // Lots of error checking and exception throwing - if (source == null) { - throw new NullPointerException("Cannot decode null source array."); - } // end if - if (off < 0 || off + len > source.length) { - throw new IllegalArgumentException( - String.format("Source array with length %d cannot have offset of %d and process %d bytes.", - source.length, off, len)); - } // end if - - if (len == 0) { - return new byte[0]; - } - else if (len < 4) { - throw new IllegalArgumentException( - "Base64-encoded string must have at least four characters, but length specified was " + len); - } // end if - - byte[] DECODABET = getDecodabet(options); - - int len34 = len * 3 / 4; // Estimate on array size - byte[] outBuff = new byte[len34]; // Upper limit on size of output - int outBuffPosn = 0; // Keep track of where we're writing - - byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space - int b4Posn = 0; // Keep track of four byte input buffer - int i = 0; // Source array counter - byte sbiDecode = 0; // Special value from DECODABET - - for (i = off; i < off + len; i++) { // Loop through source - - sbiDecode = DECODABET[source[i] & 0xFF]; - - // White space, Equals sign, or legit Base64 character - // Note the values such as -5 and -9 in the - // DECODABETs at the top of the file. - if (sbiDecode >= WHITE_SPACE_ENC) { - if (sbiDecode >= EQUALS_SIGN_ENC) { - b4[b4Posn++] = source[i]; // Save non-whitespace - if (b4Posn > 3) { // Time to decode? - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options); - b4Posn = 0; - - // If that was the equals sign, break out of 'for' loop - if (source[i] == EQUALS_SIGN) { - break; - } - } - } - } - else { - // There's a bad input character in the Base64 stream. - throw new InvalidBase64CharacterException(String - .format("Bad Base64 input character decimal %d in array position %d", (source[i]) & 0xFF, i)); - } - } - - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } - - @SuppressWarnings("serial") - static class InvalidBase64CharacterException extends IllegalArgumentException { - - InvalidBase64CharacterException(String message) { - super(message); - } - - } - -} diff --git a/crypto/src/test/java/org/springframework/security/crypto/codec/Base64Tests.java b/crypto/src/test/java/org/springframework/security/crypto/codec/Base64Tests.java deleted file mode 100644 index e53eddc564..0000000000 --- a/crypto/src/test/java/org/springframework/security/crypto/codec/Base64Tests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.crypto.codec; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -/** - * @author Luke Taylor - */ -@SuppressWarnings("deprecation") -public class Base64Tests { - - @Test - public void isBase64ReturnsTrueForValidBase64() { - assertThat(Base64.isBase64(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D' })).isTrue(); - } - - @Test - public void isBase64ReturnsFalseForInvalidBase64() { - // Include invalid '`' character - assertThat(Base64.isBase64(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) '`' })).isFalse(); - } - - @Test - public void isBase64RejectsNull() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> Base64.isBase64(null)); - } - - @Test - public void isBase64RejectsInvalidLength() { - assertThatIllegalArgumentException().isThrownBy(() -> Base64.isBase64(new byte[] { (byte) 'A' })); - } - -} From 7de4217469e3d24790a1dc08cb47f7a1f851f58e Mon Sep 17 00:00:00 2001 From: Kevin Yue Date: Sun, 16 Mar 2025 23:06:22 +0800 Subject: [PATCH 464/504] Don't cache WebSocket request PR gh-16741 Signed-off-by: Kevin Yue --- .../web/configurers/RequestCacheConfigurer.java | 6 +++++- .../RequestCacheConfigurerTests.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java index ca59dd5b05..3be334a17d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -145,6 +145,9 @@ public final class RequestCacheConfigurer> RequestMatcher notFavIcon = new NegatedRequestMatcher(getFaviconRequestMatcher()); RequestMatcher notXRequestedWith = new NegatedRequestMatcher( new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); + RequestMatcher notWebSocket = new NegatedRequestMatcher( + new RequestHeaderRequestMatcher("Upgrade", "websocket")); + boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null; List matchers = new ArrayList<>(); if (isCsrfEnabled) { @@ -156,6 +159,7 @@ public final class RequestCacheConfigurer> matchers.add(notXRequestedWith); matchers.add(notMatchingMediaType(http, MediaType.MULTIPART_FORM_DATA)); matchers.add(notMatchingMediaType(http, MediaType.TEXT_EVENT_STREAM)); + matchers.add(notWebSocket); return new AndRequestMatcher(matchers); } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java index 32e631a3ee..5155d32a45 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java @@ -169,6 +169,23 @@ public class RequestCacheConfigurerTests { this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); } + @Test + public void getWhenBookmarkedRequestIsWebSocketThenPostAuthenticationRedirectsToRoot() throws Exception { + this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire(); + MockHttpServletRequestBuilder request = get("/messages").header("Upgrade", "websocket"); + // @formatter:off + MockHttpSession session = (MockHttpSession) this.mvc.perform(request) + .andExpect(redirectedUrl("http://localhost/login")) + .andReturn() + .getRequest() + .getSession(); + // @formatter:on + // ignores websocket + // This is desirable since websocket requests are typically not invoked + // directly from the browser and we don't want the browser to replay them + this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); + } + @Test public void getWhenBookmarkedRequestIsAllMediaTypeThenPostAuthenticationRemembers() throws Exception { this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire(); From 7587048f957efb2888d5b4bccd3cc790a034f1d2 Mon Sep 17 00:00:00 2001 From: DingHao Date: Thu, 9 Jan 2025 10:02:08 +0800 Subject: [PATCH 465/504] Add default authorizationRequestBaseUri to DefaultOAuth2AuthorizationRequestResolver Closes gh-16383 Signed-off-by: DingHao --- .../DefaultOAuth2AuthorizationRequestResolver.java | 11 +++++++++++ ...faultOAuth2AuthorizationRequestResolverTests.java | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java index a2297accd7..5ad816f7d4 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java @@ -86,6 +86,17 @@ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2Au private Consumer authorizationRequestCustomizer = (customizer) -> { }; + /** + * Constructs a {@code DefaultOAuth2AuthorizationRequestResolver} using the provided + * parameters. + * @param clientRegistrationRepository the repository of client registrations + * authorization requests + */ + public DefaultOAuth2AuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) { + this(clientRegistrationRepository, + OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); + } + /** * Constructs a {@code DefaultOAuth2AuthorizationRequestResolver} using the provided * parameters. diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java index a0abf7132e..7c718c990e 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java @@ -568,6 +568,18 @@ public class DefaultOAuth2AuthorizationRequestResolverTests { + "nonce=([a-zA-Z0-9\\-\\.\\_\\~]){43}&" + "appid=client-id"); } + @Test + public void resolveWhenAuthorizationRequestNoProvideAuthorizationRequestBaseUri() { + OAuth2AuthorizationRequestResolver resolver = new DefaultOAuth2AuthorizationRequestResolver( + this.clientRegistrationRepository); + String requestUri = this.authorizationRequestBaseUri + "/" + this.registration2.getRegistrationId(); + MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri); + request.setServletPath(requestUri); + OAuth2AuthorizationRequest authorizationRequest = resolver.resolve(request); + assertThat(authorizationRequest.getRedirectUri()) + .isEqualTo("http://localhost/login/oauth2/code/" + this.registration2.getRegistrationId()); + } + @Test public void resolveWhenAuthorizationRequestProvideCodeChallengeMethod() { ClientRegistration clientRegistration = this.pkceClientRegistration; From e37424c6374ceb150419768a1b2cf2ce2f37e507 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:36:22 -0500 Subject: [PATCH 466/504] Fix cycle in DefaultOAuth2AuthorizationRequestResolver DefaultOAuth2AuthorizationRequestResolver should not depend on OAuth2AuthorizationRequestRedirectFilter because OAuth2AuthorizationRequestRedirectFilter already depends on DefaultOAuth2AuthorizationRequestResolver. OAuth2AuthorizationRequestRedirectFilter also takes advantage of the new constructor that defaults the base uri. Polishes gh-16384 --- .../web/DefaultOAuth2AuthorizationRequestResolver.java | 8 ++++++-- .../web/OAuth2AuthorizationRequestRedirectFilter.java | 9 +++------ .../DefaultOAuth2AuthorizationRequestResolverTests.java | 6 ++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java index 5ad816f7d4..4014e27742 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolver.java @@ -66,6 +66,11 @@ import org.springframework.web.util.UriComponentsBuilder; */ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { + /** + * The default base {@code URI} used for authorization requests. + */ + public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization"; + private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId"; private static final char PATH_DELIMITER = '/'; @@ -93,8 +98,7 @@ public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2Au * authorization requests */ public DefaultOAuth2AuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) { - this(clientRegistrationRepository, - OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); + this(clientRegistrationRepository, DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); } /** diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationRequestRedirectFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationRequestRedirectFilter.java index 65d0be3123..bbf9be1363 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationRequestRedirectFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationRequestRedirectFilter.java @@ -87,7 +87,7 @@ public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilt /** * The default base {@code URI} used for authorization requests. */ - public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization"; + public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = DefaultOAuth2AuthorizationRequestResolver.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer(); @@ -107,7 +107,7 @@ public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilt * @param clientRegistrationRepository the repository of client registrations */ public OAuth2AuthorizationRequestRedirectFilter(ClientRegistrationRepository clientRegistrationRepository) { - this(clientRegistrationRepository, DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); + this(new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository)); } /** @@ -119,10 +119,7 @@ public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilt */ public OAuth2AuthorizationRequestRedirectFilter(ClientRegistrationRepository clientRegistrationRepository, String authorizationRequestBaseUri) { - Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); - Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty"); - this.authorizationRequestResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, - authorizationRequestBaseUri); + this(new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationRequestBaseUri)); } /** diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java index 7c718c990e..1382a0368f 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/DefaultOAuth2AuthorizationRequestResolverTests.java @@ -97,6 +97,12 @@ public class DefaultOAuth2AuthorizationRequestResolverTests { this.authorizationRequestBaseUri); } + @Test + void authorizationRequestBaseUriEqualToRedirectFilter() { + assertThat(DefaultOAuth2AuthorizationRequestResolver.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI) + .isEqualTo(OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); + } + @Test public void constructorWhenClientRegistrationRepositoryIsNullThenThrowIllegalArgumentException() { assertThatIllegalArgumentException() From f2a88f99a6e0c9c7e16ce5485435638deccb98b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 03:51:02 +0000 Subject: [PATCH 467/504] Bump org.springframework.data:spring-data-bom --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 3c3ee7853800f409b9736fe62fa89a65a528cc26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 03:51:10 +0000 Subject: [PATCH 468/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From c7a54d456fb137e096fe966c52a3e78fdfcfabb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 03:51:29 +0000 Subject: [PATCH 469/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 325e36b3e2498d4179b5780364745f92f854937a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 03:54:56 +0000 Subject: [PATCH 470/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..7197d56f69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From b0a0501e2111ab362f7818556367cee857ec799d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:00:07 +0000 Subject: [PATCH 471/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 75bf24cd2b42d8f1cf5b97000a606c3e5ab674c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:00:26 +0000 Subject: [PATCH 472/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 9699996edb9fde88952366abe4b742ffd55a6d03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:00:30 +0000 Subject: [PATCH 473/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.19.Final --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.19.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..809aa8349d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.19.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 80813b4ac5b560349d92e0a6d1dd8d93820753a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:01:31 +0000 Subject: [PATCH 474/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..c465d30087 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 267bcc870548e475a2861ea7f5e3ad6f9c0f117b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:01:54 +0000 Subject: [PATCH 475/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From bc6d5ffa34d9fbf93750682a60293678b7686c4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:34:54 +0000 Subject: [PATCH 476/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From f34337a4e0708ff9bbb9baafcd8a530b13b38f68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:36:16 +0000 Subject: [PATCH 477/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..edb76aeb40 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-maven-resolver = "1.9.23" From a373ebd0091f2184675620419add230d751c189b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:36:51 +0000 Subject: [PATCH 478/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..7ec855332a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From cca38a0067e0d3e090860f404726dacd1a53f87a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:37:39 +0000 Subject: [PATCH 479/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a12ae45547 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 91a5a97c504b5a4fc5660c24e783f52a006be1b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:38:00 +0000 Subject: [PATCH 480/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.4.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.4.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/commits) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.4.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..55c7110c4b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.4.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0" From 8f0f3343fa6bcfab46d39286fb10a59f954eaa9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:38:00 +0000 Subject: [PATCH 481/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..937f843bcf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 11774cd32a3b62ef6569d4b1fd4f0befde926466 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:38:20 +0000 Subject: [PATCH 482/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a716c7468a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 08cdf7d53b3753e6cb6aba517f09755918b48cac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:39:09 +0000 Subject: [PATCH 483/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..89b3f104a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 68fe473741d9dca83283c9f8d589c92dd98b0e1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:43:21 +0000 Subject: [PATCH 484/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.19.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.19.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/commits) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.19.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..78786aec3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.19.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From e7145680a927b24939ed8119ef1a4a66b380d702 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 04:44:04 +0000 Subject: [PATCH 485/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..c98e12ecdf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From dcc757eaf0c45fdfb15c41e562750cd7c8fe6f57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:21:58 +0000 Subject: [PATCH 486/504] Bump org.springframework.data:spring-data-bom from 2024.1.6 to 2024.1.7 Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.1.6 to 2024.1.7. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.1.6...2024.1.7) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.1.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..78d46328ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From bd4cdf8c222beb14990c6e488e882c1cbfc9dd97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:25:42 +0000 Subject: [PATCH 487/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a716c7468a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -90,7 +90,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From fc754374a09bbc73833c57d66b8a66ad902271af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:36:31 +0000 Subject: [PATCH 488/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..760e98560c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2023.0.19" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 3882cc2bf5cf6e71c8744ae853cbd09df7c8a629 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:37:51 +0000 Subject: [PATCH 489/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.19.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.19.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/commits) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.19.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..78786aec3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.19.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 127f2f3f52e4fc775a92ffad57c818fa2ee97a07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:41:39 +0000 Subject: [PATCH 490/504] Bump org.hibernate.orm:hibernate-core from 6.6.17.Final to 6.6.19.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 6.6.17.Final to 6.6.19.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/commits) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.19.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..809aa8349d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.19.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25" From 74a5e2c569dca227462fe0a2f1db5b2e63503f78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:48:36 +0000 Subject: [PATCH 491/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..787dd450ad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0" org-mockito = "5.14.2" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From 6ab3e2b31d4829b5bbd9a433636aeb590e944bbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:53:30 +0000 Subject: [PATCH 492/504] Bump org.springframework:spring-framework-bom from 6.2.7 to 6.2.8 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.7...v6.2.8) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..f38fb1f764 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.10.2" org-mockito = "5.17.0" org-opensaml = "4.3.2" org-opensaml5 = "5.1.2" -org-springframework = "6.2.7" +org-springframework = "6.2.8" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From f7962003ec55bca16d9aecf0c914e13c464da286 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:53:57 +0000 Subject: [PATCH 493/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6377c39c2..a12ae45547 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 8603a9ad34748d8d19479b1a311d0c5a22fb3613 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:55:40 +0000 Subject: [PATCH 494/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..c465d30087 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-directory-server = "1.5.5" From 1b472ddeb188143f463418584b15c5db68fc6ec7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:57:36 +0000 Subject: [PATCH 495/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..7197d56f69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.1.1" org-apache-directory-server = "1.5.5" From 700b4a17f8b7f5a1c7333338f62a632175a394ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:03:44 +0000 Subject: [PATCH 496/504] Bump org.springframework:spring-framework-bom from 6.1.20 to 6.1.21 Bumps [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework) from 6.1.20 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.20...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 6.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..36d70d0ff0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-jetbrains-kotlin = "1.9.25" org-jetbrains-kotlinx = "1.8.1" org-mockito = "5.11.0" org-opensaml = "4.3.2" -org-springframework = "6.1.20" +org-springframework = "6.1.21" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" From e8566fb722ab482792dacc5e2b0619bc7dd1ed24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:06:52 +0000 Subject: [PATCH 497/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..d69c3f634c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,7 +85,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 3f9bb81164e621ca78d7ca25041360735e332d21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:16:03 +0000 Subject: [PATCH 498/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..937f843bcf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,7 +83,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2025.1.0-SNAPSHOT" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From beca5ccbad0ddec00cecd9a17e129a359295ca7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:22:53 +0000 Subject: [PATCH 499/504] Bump org.springframework.ldap:spring-ldap-core from 3.2.12 to 3.2.13 Bumps [org.springframework.ldap:spring-ldap-core](https://github.com/spring-projects/spring-ldap) from 3.2.12 to 3.2.13. - [Release notes](https://github.com/spring-projects/spring-ldap/releases) - [Changelog](https://github.com/spring-projects/spring-ldap/blob/main/changelog.txt) - [Commits](https://github.com/spring-projects/spring-ldap/compare/3.2.12...3.2.13) --- updated-dependencies: - dependency-name: org.springframework.ldap:spring-ldap-core dependency-version: 3.2.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8754f41e4f..4208ab834d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6" -org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" +org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From 33351102c7a15031c3be60fd3e50b973156a9214 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:29:51 +0000 Subject: [PATCH 500/504] Bump org.springframework.data:spring-data-bom Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2024.0.12 to 2024.0.13. - [Release notes](https://github.com/spring-projects/spring-data-bom/releases) - [Commits](https://github.com/spring-projects/spring-data-bom/compare/2024.0.12...2024.0.13) --- updated-dependencies: - dependency-name: org.springframework.data:spring-data-bom dependency-version: 2024.0.13 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94b8454fc8..a661b77884 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,7 +84,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3" org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36" org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17" -org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.12" +org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.0.13" org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12" org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" } org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0" From a979094a48d10561d09cc4e30dfe8c0b44dff478 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:33:39 +0000 Subject: [PATCH 501/504] Bump org.hibernate.orm:hibernate-core from 7.0.1.Final to 7.0.4.Final Bumps [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm) from 7.0.1.Final to 7.0.4.Final. - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/7.0.4/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/7.0.1...7.0.4) --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 7.0.4.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..55c7110c4b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on", org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" } org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" } org-hamcrest = "org.hamcrest:hamcrest:2.2" -org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.1.Final" +org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:7.0.4.Final" org-hsqldb = "org.hsqldb:hsqldb:2.7.4" org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0" From 4ca80cdd2846e5080151983728398d1fcd22bdcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:59:55 +0000 Subject: [PATCH 502/504] Bump io.mockk:mockk from 1.14.2 to 1.14.4 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.14.2 to 1.14.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/1.14.2...1.14.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-version: 1.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..89b3f104a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ com-unboundid-unboundid-ldapsdk7 = "com.unboundid:unboundid-ldapsdk:7.0.1" commons-collections = "commons-collections:commons-collections:3.2.2" io-micrometer-context-propagation = "io.micrometer:context-propagation:1.1.3" io-micrometer-micrometer-observation = "io.micrometer:micrometer-observation:1.14.8" -io-mockk = "io.mockk:mockk:1.14.2" +io-mockk = "io.mockk:mockk:1.14.4" io-projectreactor-reactor-bom = "io.projectreactor:reactor-bom:2025.0.0-M4" io-rsocket-rsocket-bom = { module = "io.rsocket:rsocket-bom", version.ref = "io-rsocket" } io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javaformat:spring-javaformat-checkstyle", version.ref = "io-spring-javaformat" } From 0cc49b87881821e4ce69dbc5ce6cf825e868efdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 08:00:16 +0000 Subject: [PATCH 503/504] Bump com.fasterxml.jackson:jackson-bom from 2.19.0 to 2.19.1 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.19.0 to 2.19.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.19.0...jackson-bom-2.19.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..7ec855332a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ org-springframework = "7.0.0-SNAPSHOT" [libraries] ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18" -com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.0" +com-fasterxml-jackson-jackson-bom = "com.fasterxml.jackson:jackson-bom:2.19.1" com-google-inject-guice = "com.google.inject:guice:3.0" com-netflix-nebula-nebula-project-plugin = "com.netflix.nebula:nebula-project-plugin:8.2.0" com-nimbusds-nimbus-jose-jwt = "com.nimbusds:nimbus-jose-jwt:9.37.3" From 2cccfe88a178cb17b2c89600f2196dc59ca9d52d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 08:00:31 +0000 Subject: [PATCH 504/504] Bump io-spring-javaformat from 0.0.46 to 0.0.47 Bumps `io-spring-javaformat` from 0.0.46 to 0.0.47. Updates `io.spring.javaformat:spring-javaformat-checkstyle` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) Updates `io.spring.javaformat:spring-javaformat-gradle-plugin` from 0.0.46 to 0.0.47 - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.46...v0.0.47) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.spring.javaformat:spring-javaformat-gradle-plugin dependency-version: 0.0.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea4397a39b..edb76aeb40 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] com-squareup-okhttp3 = "3.14.9" io-rsocket = "1.1.5" -io-spring-javaformat = "0.0.46" +io-spring-javaformat = "0.0.47" io-spring-nohttp = "0.0.11" jakarta-websocket = "2.2.0" org-apache-maven-resolver = "1.9.23"