-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Description
Describe the bug
When a SAML IdP is configured to add a OneTimeUse condition to the SAML Assertion, the OpenSamlAuthenticationProvider throws a Saml2Exception and claims that the OneTimeUse condition is an unknown condition.
To Reproduce
- Configure an IdP to send the OneTimeUse condition
- Attempt to authenticate to the application
- Authentication fails due to the Saml2Exception
In Keycloak, the client registration can be configured with the Include OneTimeUse Condition slider to replicate this issue.
Expected behavior
This condition should be parsed and handled appropriately.
Debug Log output
2020-06-26 10:30:35.002 DEBUG 12544 --- [nio-8080-exec-3] .p.s.s.f.Saml2WebSsoAuthenticationFilter : Request is to process authentication
2020-06-26 10:30:35.070 DEBUG 12544 --- [nio-8080-exec-3] s.s.p.s.a.OpenSamlAuthenticationProvider : Validating SAML response from <IdP>
2020-06-26 10:30:35.102 DEBUG 12544 --- [nio-8080-exec-3] s.s.p.s.a.OpenSamlAuthenticationProvider : Validating 1 assertions
2020-06-26 10:30:35.109 DEBUG 12544 --- [nio-8080-exec-3] s.s.p.s.a.OpenSamlAuthenticationProvider : Found 1 validation errors in SAML response [ID_7e615c61-9dda-4629-90fa-989a817c3282]
2020-06-26 10:30:35.109 DEBUG 12544 --- [nio-8080-exec-3] .p.s.s.f.Saml2WebSsoAuthenticationFilter : Authentication request failed: Saml2AuthenticationException{error=[invalid_assertion] Invalid assertion [ID_573ac246-7ea6-4098-af2a-2c97296011dc] for SAML response [ID_7e615c61-9dda-4629-90fa-989a817c3282]}
org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException: An error occurred while validating the assertion: Unknown Condition '{urn:oasis:names:tc:SAML:2.0:assertion}OneTimeUse' of type 'null' in assertion 'ID_573ac246-7ea6-4098-af2a-2c97296011dc'
at org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.authException(OpenSamlAuthenticationProvider.java:510)
at org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.validateResponse(OpenSamlAuthenticationProvider.java:320)
at org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.authenticate(OpenSamlAuthenticationProvider.java:205)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
at org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter.attemptAuthentication(Saml2WebSsoAuthenticationFilter.java:109)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:239)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter.doFilterInternal(Saml2WebSsoAuthenticationRequestFilter.java:146)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:353)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:223)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:141)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.springframework.security.saml2.Saml2Exception: An error occurred while validating the assertion: Unknown Condition '{urn:oasis:names:tc:SAML:2.0:assertion}OneTimeUse' of type 'null' in assertion 'ID_573ac246-7ea6-4098-af2a-2c97296011dc'
at org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.validateAssertion(OpenSamlAuthenticationProvider.java:403)
at org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.validateResponse(OpenSamlAuthenticationProvider.java:317)
... 61 common frames omitted
Sample
I've added a OneTimeUse condition test in a commit to my fork here plnordquist@0e5b5a8a34 which replicates this failure.
I think fixing this requires adding a OneTimeUseConditionValidator
to the list of ConditionValidators
in the OpenSamlAuthenticationProvider
but that validator seems to require a ReplayCache
that enforces this condition so tokens cannot be replayed.