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 7079b9e0c1..c980777e88 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 @@ -46,10 +46,16 @@ import org.springframework.security.saml2.provider.service.web.Saml2Authenticati import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml3AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationConverter; +import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; +import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +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; @@ -263,8 +269,7 @@ public final class Saml2LoginConfigurer> this.updateAuthenticationDefaults(); this.updateAccessDefaults(http); String loginUrl = providerUrlMap.entrySet().iterator().next().getKey(); - final LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(loginUrl); - registerAuthenticationEntryPoint(http, entryPoint); + registerAuthenticationEntryPoint(http, getLoginEntryPoint(http, loginUrl)); } else { super.init(http); @@ -306,6 +311,22 @@ public final class Saml2LoginConfigurer> return this.relyingPartyRegistrationRepository; } + private AuthenticationEntryPoint getLoginEntryPoint(B http, String providerLoginPage) { + RequestMatcher loginPageMatcher = new AntPathRequestMatcher(this.getLoginPage()); + RequestMatcher faviconMatcher = new AntPathRequestMatcher("/favicon.ico"); + RequestMatcher defaultEntryPointMatcher = this.getAuthenticationEntryPointMatcher(http); + RequestMatcher defaultLoginPageMatcher = new AndRequestMatcher( + new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher); + RequestMatcher notXRequestedWith = new NegatedRequestMatcher( + new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest")); + LinkedHashMap entryPoints = new LinkedHashMap<>(); + entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)), + new LoginUrlAuthenticationEntryPoint(providerLoginPage)); + DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints); + loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint()); + return loginEntryPoint; + } + private void setAuthenticationRequestRepository(B http, Saml2WebSsoAuthenticationFilter saml2WebSsoAuthenticationFilter) { saml2WebSsoAuthenticationFilter.setAuthenticationRequestRepository(getAuthenticationRequestRepository(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 030a485c45..7917aa7149 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 @@ -40,6 +40,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.core.convert.converter.Converter; +import org.springframework.http.MediaType; import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -350,6 +351,16 @@ public class Saml2LoginConfigurerTests { verify(authenticationConverter).convert(any(HttpServletRequest.class)); } + // gh-11657 + @Test + public void getFaviconWhenDefaultConfigurationThenDoesNotSaveAuthnRequest() throws Exception { + this.spring.register(Saml2LoginConfig.class).autowire(); + this.mvc.perform(get("/favicon.ico").accept(MediaType.TEXT_HTML)).andExpect(status().isFound()) + .andExpect(redirectedUrl("http://localhost/login")); + this.mvc.perform(get("/").accept(MediaType.TEXT_HTML)).andExpect(status().isFound()) + .andExpect(redirectedUrl("http://localhost/saml2/authenticate/registration-id")); + } + private void validateSaml2WebSsoAuthenticationFilterConfiguration() { // get the OpenSamlAuthenticationProvider Saml2WebSsoAuthenticationFilter filter = getSaml2SsoFilter(this.springSecurityFilterChain);