Describe the bug ValidationContext is lost unexpectedly causing InResponseTo validation to fail
To Reproduce Set a breakpoint here: https://github.com/tyler555g/SpringSecuritySAMLPOC/blob/main/src/main/java/com/SpringSecuritySSOPOC/saml/config/Saml2LoginSecurityConfig.java#L162 Run backend. Create a login call. Wait for a couple minutes. Create another login call. Login call occasionally loses ValidationContext. See logs attached and working code example.
Expected behavior InResponseTo validation passes correctly
Sample https://github.com/tyler555g/SpringSecuritySAMLPOC/blob/main/src/main/java/com/SpringSecuritySSOPOC/saml/config/Saml2LoginSecurityConfig.java#L162 SpringSecurityLogsNoResponseTo20250109.txt
Log snippets:
2025-01-09T14:53:11.642-05:00 TRACE 29112 --- [nio-8091-exec-5] o.o.s.s.a.SAML20AssertionValidator : SAML 2 Assertion ValidationContext - static parameters: {saml2.ValidIssuers=[redacted], saml2.SubjectConfirmation.ValidInResponseTo=null, saml2.ClockSkew=PT5M, saml2.Conditions.ValidAudiences=[http://localhost:8091/saml2/service-provider-metadata/azure-ad], saml2.SubjectConfirmation.ValidRecipients=[http://localhost:8091/login/saml2/sso/azure-ad]} 2025-01-09T14:53:11.642-05:00 TRACE 29112 --- [nio-8091-exec-5] o.o.s.s.a.SAML20AssertionValidator : SAML 2 Assertion ValidationContext - dynamic parameters: {} 2025-01-09T14:53:11.642-05:00 DEBUG 29112 --- [nio-8091-exec-5] o.o.s.s.a.SAML20AssertionValidator : Evaluating Assertion Issuer of : redacted 2025-01-09T14:53:11.642-05:00 DEBUG 29112 --- [nio-8091-exec-5] o.o.s.s.a.SAML20AssertionValidator : Matched valid issuer: redacted 2025-01-09T14:53:11.642-05:00 DEBUG 29112 --- [nio-8091-exec-5] o.o.s.s.a.SAML20AssertionValidator : No Conditions were indicated as required ...
Comment From: jzheaux
Hi, @tyler555g, thanks for the report.
I can't use the sample yet because it doesn't appear to start up. If I use the local profile, then I get the following exception:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'saml.decrypt' in value "${saml.decrypt}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-6.1.13.jar:6.1.13]
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-6.1.13.jar:6.1.13]
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) ~[spring-core-6.1.13.jar:6.1
....
When I use the default profile, then I get the following:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'backend.url' in value "${backend.url}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-6.1.13.jar:6.1.13]
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-6.1.13.jar:6.1.13]
...
Can you update the code so that it starts up, and then I'd be happy to try and reproduce?
Comment From: jzheaux
One thing that strikes me is that OpenSAML's InResponseTo property is present, but null. That likely means that Spring Security couldn't find the associated AuthnRequest to compare to the value.
It makes me wonder if the issue is a race condition, perhaps via the browser, where the session cookie is different, so the Saml2AuthenticationRequestRepository is empty.
Comment From: tyler555g
Hi, @tyler555g, thanks for the report.
I can't use the sample yet because it doesn't appear to start up. If I use the
localprofile, then I get the following exception:Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'saml.decrypt' in value "${saml.decrypt}" at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-6.1.13.jar:6.1.13] at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-6.1.13.jar:6.1.13] at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) ~[spring-core-6.1.13.jar:6.1 .... When I use the default profile, then I get the following:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'backend.url' in value "${backend.url}" at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-6.1.13.jar:6.1.13] at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-6.1.13.jar:6.1.13] ... Can you update the code so that it starts up, and then I'd be happy to try and reproduce?
https://github.com/tyler555g/SpringSecuritySAMLPOC/blob/main/src/main/resources/application-local.properties
#You must either replace SAML_DECRYPTION_CERTIFICATE, SAML_SIGNING_KEY and IDP_METADATA_URL with your own values or specify them in environment variables
#X509 certificate used to decrypt incoming SAML messages
saml.decryption.certificate=${SAML_DECRYPTION_CERTIFICATE}
#RSA key used to sign AuthnRequest messages
saml.signing.key=${SAML_SIGNING_KEY}
security.jwt.token.expire-hour-length=12
webapp.url=http://localhost:4200/
backend.url=http://localhost:8091/
saml.idp.metadata-url=${IDP_METADATA_URL}
I've updated the application-local.properties with a comment explaining use of the environment variables. Please replace with your own as configured for your specific IDP.
Comment From: tyler555g
One thing that strikes me is that OpenSAML's InResponseTo property is present, but
null. That likely means that Spring Security couldn't find the associatedAuthnRequestto compare to the value.It makes me wonder if the issue is a race condition, perhaps via the browser, where the session cookie is different, so the
Saml2AuthenticationRequestRepositoryis empty.
Could you point to additional logging or tracing I can do to support this hypothesis? I am able to reproduce and capture the entire session in HTTP Toolkit.
Comment From: jzheaux
I am able to reproduce and capture the entire session in HTTP Toolkit.
Yes, I believe that may help. Are you able to post the HTTP request and response headers of the full authentication flow? Specifically, the /saml2/authenticate/azure-ad request and response, the IdP's response to the AuthnRequest, and the /login/saml2/sso/azure-ad request and response.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.