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 315039dd70..7079b9e0c1 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 @@ -109,7 +109,7 @@ public final class Saml2LoginConfigurer> private String loginPage; - private String authenticationRequestUri = "/saml2/authenticate/{registrationId}"; + private String authenticationRequestUri = Saml2AuthenticationRequestResolver.DEFAULT_AUTHENTICATION_REQUEST_URI; private Saml2AuthenticationRequestResolver authenticationRequestResolver; @@ -186,6 +186,24 @@ public final class Saml2LoginConfigurer> return this; } + /** + * Customize the URL that the SAML Authentication Request will be sent to. + * @param authenticationRequestUri the URI to use for the SAML 2.0 Authentication + * Request + * @return the {@link Saml2LoginConfigurer} for further configuration + * @since 6.0 + */ + public Saml2LoginConfigurer authenticationRequestUri(String authenticationRequestUri) { + // OpenSAML 3 is no longer supported by spring security + if (version().startsWith("3")) { + return this; + } + Assert.state(authenticationRequestUri.contains("{registrationId}"), + "authenticationRequestUri must contain {registrationId} path variable"); + this.authenticationRequestUri = authenticationRequestUri; + return this; + } + /** * Specifies the URL to validate the credentials. If specified a custom URL, consider * specifying a custom {@link AuthenticationConverter} via @@ -307,7 +325,11 @@ public final class Saml2LoginConfigurer> return bean; } if (version().startsWith("4")) { - return new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationResolver(http)); + OpenSaml4AuthenticationRequestResolver openSaml4AuthenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver( + relyingPartyRegistrationResolver(http)); + openSaml4AuthenticationRequestResolver + .setRequestMatcher(new AntPathRequestMatcher(this.authenticationRequestUri)); + return openSaml4AuthenticationRequestResolver; } return new OpenSaml3AuthenticationRequestResolver(relyingPartyRegistrationResolver(http)); } 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 94e117769b..5faf38ddbc 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 @@ -297,6 +297,17 @@ public class Saml2LoginConfigurerTests { verify(repository).removeAuthenticationRequest(any(HttpServletRequest.class), any(HttpServletResponse.class)); } + @Test + public void authenticationRequestWhenCustomAuthenticationRequestUriRepositoryThenUses() throws Exception { + this.spring.register(CustomAuthenticationRequestUriCustomAuthenticationConverter.class).autowire(); + MockHttpServletRequestBuilder request = get("/custom/auth/registration-id"); + this.mvc.perform(request).andExpect(status().isFound()); + Saml2AuthenticationRequestRepository repository = this.spring.getContext() + .getBean(Saml2AuthenticationRequestRepository.class); + verify(repository).saveAuthenticationRequest(any(AbstractSaml2AuthenticationRequest.class), + any(HttpServletRequest.class), any(HttpServletResponse.class)); + } + @Test public void saml2LoginWhenLoginProcessingUrlWithoutRegistrationIdAndDefaultAuthenticationConverterThenValidates() { assertThatExceptionOfType(BeanCreationException.class) @@ -601,6 +612,30 @@ public class Saml2LoginConfigurerTests { } + @EnableWebSecurity + @Import(Saml2LoginConfigBeans.class) + static class CustomAuthenticationRequestUriCustomAuthenticationConverter { + + private final Saml2AuthenticationRequestRepository repository = mock( + Saml2AuthenticationRequestRepository.class); + + @Bean + Saml2AuthenticationRequestRepository authenticationRequestRepository() { + return this.repository; + } + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests((authz) -> authz.anyRequest().authenticated()) + .saml2Login((saml2) -> saml2.authenticationRequestUri("/custom/auth/{registrationId}")); + // @formatter:on + return http.build(); + } + + } + @EnableWebSecurity @Import(Saml2LoginConfigBeans.class) static class CustomLoginProcessingUrlCustomAuthenticationConverter { diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSamlAuthenticationRequestResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSamlAuthenticationRequestResolver.java index 108d72724f..79c2881a1b 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSamlAuthenticationRequestResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSamlAuthenticationRequestResolver.java @@ -59,9 +59,6 @@ class OpenSamlAuthenticationRequestResolver { static { OpenSamlInitializationService.initialize(); } - - private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/saml2/authenticate/{registrationId}"); - private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver; private final AuthnRequestBuilder authnRequestBuilder; @@ -72,6 +69,9 @@ class OpenSamlAuthenticationRequestResolver { private final NameIDBuilder nameIdBuilder; + private RequestMatcher requestMatcher = new AntPathRequestMatcher( + Saml2AuthenticationRequestResolver.DEFAULT_AUTHENTICATION_REQUEST_URI); + private Converter relayStateResolver = (request) -> UUID.randomUUID().toString(); /** diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2AuthenticationRequestResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2AuthenticationRequestResolver.java index 69635d0c00..45e64aeff7 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2AuthenticationRequestResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/Saml2AuthenticationRequestResolver.java @@ -29,6 +29,8 @@ import org.springframework.security.saml2.provider.service.authentication.Abstra */ public interface Saml2AuthenticationRequestResolver { + String DEFAULT_AUTHENTICATION_REQUEST_URI = "/saml2/authenticate/{registrationId}"; + T resolve(HttpServletRequest request); }