1
0
mirror of synced 2026-08-31 22:46:02 +00:00

Support Continue Filter Chain When No Relying Party

Closes gh-16000
This commit is contained in:
Josh Cummings
2025-04-03 15:32:04 -06:00
parent 5436fd5574
commit 67c21de1cf
3 changed files with 108 additions and 1 deletions
@@ -54,6 +54,8 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce
private Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> 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;
}
}
@@ -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<AbstractSaml2AuthenticationRequest> authenticationRequestRepository = mock(