Shinyproxy: SAML 身份验证超时 (?) 错误

创建于 2021-02-15  ·  6评论  ·  资料来源: openanalytics/shinyproxy

再一次问好! 随着我们使用 SAML 开发我们的应用程序,我们发现了一个身份验证问题,只有在某个选项卡保持打开状态一段时间后才会出现该问题(尚未确定导致问题的确切时间跨度)然后用户刷新他们的选项卡(不确定此时是否有新窗口也触发它)。 似乎在这段不活动时间之后,ShinyProxy 尝试重新进行身份验证,但由于某种原因失败了。 我找到的唯一解决方案是在浏览器中为我们的 IdP (auth.company.com) 清除站点数据。 一旦完成,事情就会按预期进行。

发生这种情况时,ShinyProxy 尝试连续多次进行身份验证(我可以在 URL 栏中看到许多 SAML 重定向回调),但最终失败,并将我转储到http://my.company.com/app/saml /SSO出现以下错误:

image

在服务器日志中,我看到以下内容:

shinyproxy-server_1  | 2021-02-15 04:00:11.531  INFO 1 --- [  XNIO-1 task-4] o.s.security.saml.log.SAMLDefaultLogger  : AuthNRequest;SUCCESS;XXX.XX.XX.XXX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;
shinyproxy-server_1  | 2021-02-15 04:00:11.608  INFO 1 --- [  XNIO-1 task-4] colMessageXMLSignatureSecurityPolicyRule : Validation of protocol message signature succeeded, message type: {urn:oasis:names:tc:SAML:2.0:protocol}Response
shinyproxy-server_1  | 2021-02-15 04:00:11.609  INFO 1 --- [  XNIO-1 task-4] o.s.security.saml.log.SAMLDefaultLogger  : AuthNResponse;FAILURE;XXX.XX.XX.XXX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;org.springframework.security.saml.SAMLStatusException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null

奇怪的是,第一次身份验证尝试似乎成功了,但由于某种原因,ShinyProxy 不喜欢它并再次尝试。


完整的错误回溯:

~Shinyproxy-server_1 |
在 org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88)Shinyproxy-server_1 |
在 org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:219)Shinyproxy-server_1 |
在 sun.reflect.GeneratedMethodAccessor63.invoke(未知来源)Shinyproxy-server_1 |
在 java.lang.reflect.Method.invoke(Method.java:498)Shinyproxy-server_1 |
在 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205)Shinyproxy-server_1 |
在 org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)Shinyproxy-server_1 |
在 org.springframework.security.web.authentication。
在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)Shinyproxy-server_1 |
在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)Shinyproxy-server_1 |
在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)Shinyproxy-server_1 |
在 org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)Shinyproxy-server_1 |
在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)Shinyproxy-server_1 |
在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)Shinyproxy-server_1 |
在 org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)Shinyproxy-server_1 |
在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)Shinyproxy-server_1 |
在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)Shinyproxy-server_1 |
在 io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)Shinyproxy-server_1 |
在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)Shinyproxy-server_1 |
在 io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)Shinyproxy-server_1 |
在 org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)Shinyproxy-server_1 |
在 io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)Shinyproxy-server_1 |
在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)Shinyproxy-server_1 |
在 io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)Shinyproxy-server_1 |
在 io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)Shinyproxy-server_1 |
在 io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)Shinyproxy-server_1 |
在 io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)Shinyproxy-server_1 |
在 io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)Shinyproxy-server_1 |
在 io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)Shinyproxy-server_1 |
在 io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)Shinyproxy-server_1 |
在 io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)Shinyproxy-server_1 |
在 io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)Shinyproxy-server_1 |
在 org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)Shinyproxy-server_1 |
在 org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)Shinyproxy-server_1 |
在 java.lang.Thread.run(Thread.java:748)~

简单的解决方案是单击“注销”按钮,但该按钮未显示在 SAML 错误屏幕上。 调试很困难,因为我无法按需实现。 根据我的 IdP 支持人员的说法,ADFS 确实在此过程开始时发出了一个有效的令牌,因此这似乎是 ShinyProxy 如何处理它收到的令牌的本地问题。 我猜因为浏览器选项卡从未关闭,也许登录 cookie 已经过期并且没有正确更新,但我不知道我在说什么,所以请谨慎对待。

当我再次发生错误时,我会回来提供一些希望更有用的信息,但我很想知道是否有人看过这个并且对如何修复它有任何想法?

question

所有6条评论

我发现了以下问题,它指出了类似的错误消息,表明 SHA-1 和 SHA-256 签名算法之间不匹配,但如果在我们的安装中出现这种情况,我不确定为什么它在大多数情况下都能正常工作,但是在长时间不活动后会间歇性地失败,所以我认为这不是我的问题。

作为后续,我将应用程序的 SAML 部分设置为DEBUG级别日志记录,并从这些超时事件之一中看到以下内容:

shinyproxy-server_1  | 2021-02-15 21:03:14.050 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.context.SAMLContextProviderImpl  : No IDP specified, using default http://auth.company.com/adfs/services/trust
shinyproxy-server_1  | 2021-02-15 21:03:14.050 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.util.SAMLUtil          : Index for AssertionConsumerService not specified, returning default
shinyproxy-server_1  | 2021-02-15 21:03:14.051 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLEntryPoint         : Processing SSO using WebSSO profile
shinyproxy-server_1  | 2021-02-15 21:03:14.051 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.websso.WebSSOProfileImpl      : Using default consumer service with binding urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
shinyproxy-server_1  | 2021-02-15 21:03:14.052 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.storage.HttpSessionStorage    : Storing message a17g5ahbxxxxxxxxxxx454jj to session hxxxxxxJ_E8xxxxxxxxHP_TwIxxxxxxxH
shinyproxy-server_1  | 2021-02-15 21:03:14.053  INFO 1 --- [  XNIO-1 task-2] o.s.security.saml.log.SAMLDefaultLogger  : AuthNRequest;SUCCESS;XXX.XX.XXX.XX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;
shinyproxy-server_1  | 2021-02-15 21:03:14.805 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Request is to process authentication
shinyproxy-server_1  | 2021-02-15 21:03:14.806 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Attempting SAML2 authentication using profile urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser
shinyproxy-server_1  | 2021-02-15 21:03:14.811 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.processor.SAMLProcessorImpl   : Retrieving message using binding urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
shinyproxy-server_1  | 2021-02-15 21:03:14.816  INFO 1 --- [  XNIO-1 task-2] colMessageXMLSignatureSecurityPolicyRule : SAML protocol message was not signed, skipping XML signature processing
shinyproxy-server_1  | 2021-02-15 21:03:14.816 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.util.SAMLUtil          : Found endpoint org.opensaml.saml2.metadata.impl.AssertionConsumerServiceImpl<strong i="7">@6531c789</strong> for request URL https://my.company.com/app/saml/SSO based on location attribute in metadata
shinyproxy-server_1  | 2021-02-15 21:03:14.816 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.storage.HttpSessionStorage    : Message a17g5ahb0gieeh9b4e48ff6a3d454jj found in session hXmYJ_E8wf6F2plFsHP_TwIZS1Cg6n2Vu4wD4i2H, clearing
shinyproxy-server_1  | 2021-02-15 21:03:14.817 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Verifying issuer of the Response
shinyproxy-server_1  | 2021-02-15 21:03:14.817 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Verifying signature
shinyproxy-server_1  | 2021-02-15 21:03:14.820 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.t.MetadataCredentialResolver     : Added 1 credentials resolved from metadata of entity http://auth.company.com/adfs/services/trust
shinyproxy-server_1  | 2021-02-15 21:03:14.826 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Processing Bearer subject confirmation
shinyproxy-server_1  | 2021-02-15 21:03:14.836 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.s.w.WebSSOProfileConsumerImpl      : Validation of authentication statement in assertion failed, skipping
shinyproxy-server_1  | org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value 2021-02-15T15:51:35.161Z
                        ...
shinyproxy-server_1  | 2021-02-15 21:03:14.839 DEBUG 1 --- [  XNIO-1 task-2] o.s.s.saml.SAMLAuthenticationProvider    : Error validating SAML message
shinyproxy-server_1  |
shinyproxy-server_1  | org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.841  INFO 1 --- [  XNIO-1 task-2] o.s.security.saml.log.SAMLDefaultLogger  : AuthNResponse;FAILURE;XXX.XX.XXX.XX;https://my.company.com/app;http://auth.company.com/adfs/services/trust;;;org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
shinyproxy-server_1  |  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:265)
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.842  INFO 1 --- [  XNIO-1 task-2] e.o.containerproxy.service.UserService   : Authentication failure [user: ] [error: Error validating SAML message]
shinyproxy-server_1  | 2021-02-15 21:03:14.848 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
shinyproxy-server_1  |
shinyproxy-server_1  | org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.849 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Updated SecurityContextHolder to contain null Authentication
shinyproxy-server_1  | 2021-02-15 21:03:14.849 DEBUG 1 --- [  XNIO-1 task-2] o.s.security.saml.SAMLProcessingFilter   : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler<strong i="8">@19dec0b4</strong>
shinyproxy-server_1  | 2021-02-15 21:03:14.858 ERROR 1 --- [  XNIO-1 task-2] org.thymeleaf.TemplateEngine             : [THYMELEAF][XNIO-1 task-2] Exception processing template "/": Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers
shinyproxy-server_1  | org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers
                       ...
shinyproxy-server_1  |
shinyproxy-server_1  | 2021-02-15 21:03:14.861 ERROR 1 --- [  XNIO-1 task-2] io.undertow.request                      : UT005023: Exception handling request to /app/error
shinyproxy-server_1  |
shinyproxy-server_1  | org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/], template might not exist or might not be accessible by any of the configured Template Resolvers

这个序列在大约 2 秒内重复 7 次,然后 ShinyProxy 放弃并将我转储到如上所示的通用 springboot 错误页面。 两个好奇心:

1) org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value 2021-02-15T15:51:35.161Z -- 这似乎是问题的根源,但我不确定这是 IdP 方面还是 ShinyProxy 方面的问题

2) 2021-02-15 21:03:14.861 ERROR 1 --- [ XNIO-1 task-2] io.undertow.request : UT005023: Exception handling request to /app/error -- 看来我的错误模板没有正确加载。 如果是这样,我想我可以放一个指向“注销”页面的链接,用户可以点击该页面来重置他们的会话(不确定这是否可行,只是一种预感)

有任何想法吗?

相关链接:

1) https://stackoverflow.com/questions/48289763/spring-security-infinite-loop-after-initial-login-and-timeout
2) https://stackoverflow.com/questions/30528636/idp-initiated-saml-login-error-authentication-statement-is-too-old-to-be-used

链接 2 提出了几个解决方案:(1) 将maxAuthenticationAge与 ADFS 的生命周期对齐或 (2) 将forceAuthN为 true

这些是否可以从 ShinyProxy 配置中实现,或者我是否正在查看为此所需的自定义构建?

@jat255

感谢您的广泛报告和研究! 这完全是巧合:我在我们的部署中也遇到了完全相同的问题。 昨天我找到了和你一样的解决方案,我只需要测试一下:)

设置forceAuthN选项确实解决了我们的问题。 唯一的缺点是用户被迫再次提供其完整凭据,而 ADFS 认为用户的凭据仍然“足够新鲜”。 此外,从您提供的链接看来,某些 IDP 似乎忽略了此选项(例如 google)。 您可以通过在您的 saml 配置中指定它来启用forceAuthN

proxy:
  saml:
    idp-metadata-url: ... 
    ....
    force-authn: true

我们的网站上尚未记录此选项,我会处理此问题。

在 ShinyProxy 中尚未实现指定maxAuthenticationAge选项。 但是,当我看到此选项的价值时(例如,使用 google 作为 IDP),我将为此实施一个选项。

我还将尝试在CredentialsExpiredException情况下提供更有用的行为。

@LEDfan非常感谢您的及时回复和解决方案! 我已经实现了这个更改,但现在我必须等待 24 小时才能看到它是否有效:smirk:我至少已经确认我在 SAML 负载中看到了ForceAuthn="true" ,因此该选项绝对适用于 ShinyProxy边。

我认为forceAuthN选项对我们的用户来说不会太难,因为我们的大多数用户都使用与自动 Windows 凭据管理相关联的企业身份验证,因此他们无需输入任何密码即可访问SAML 保护的资源。 几天后我会在这里报告,让您知道它是否适用于我们的案例。

这似乎在过去几天里有效(没有再次看到错误),所以我会继续并关闭它。 再次感谢!

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

benkates picture benkates  ·  3评论

Bertusian picture Bertusian  ·  5评论

lucius-verus-fan picture lucius-verus-fan  ·  7评论

erossini picture erossini  ·  3评论

thomas-chauvet picture thomas-chauvet  ·  5评论