ProviderNotFoundException:未找到 ExpiringUsernameAuthenticationToken 的 AuthenticationProvider

ProviderNotFoundException: No AuthenticationProvider found for ExpiringUsernameAuthenticationToken

我们使用 Spring 安全和 Spring SAML 开发了一个应用程序,它在我们使用 SSOCircle 作为 IDP 的开发环境中运行。当我们使用他们的 IDP 进入客户的环境时,只要我们不暂停,我们就能够毫无问题地通过应用程序进行身份验证和导航。如果用户在提交之前在页面上暂停超过一分钟,应用程序将重定向到原始登录页面并且提交的数据将丢失。

日志显示:

o.s.s.w.a.ExceptionTranslationFilter
                - Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.providers.ExpiringUsernameAuthenticationToken

在此之前,您的日志大约每分钟都会显示类似于以下内容的内容:

SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.providers.ExpiringUsernameAuthenticationToken@e6313ceb: Principal: REDACTED

客户告诉我们,他们的 IDP 超时为 60 秒,偏差时间为 +-30 秒。

我们要求他们暂时将 IDP 超时调整为 30 分钟,然后我们的问题就解决了。当我们投入生产时,我们必须有 60 秒的原始设置。

我们的应用程序正在使用 SAMLAuthenticationProvider:

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.authenticationProvider(samlAuthenticationProvider());
}

@Bean
public SAMLAuthenticationProvider samlAuthenticationProvider() {
    SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider();
    samlAuthenticationProvider.setForcePrincipalAsString(false);
    samlAuthenticationProvider.setUserDetails(samlUserDetailsService);
    return samlAuthenticationProvider;
}

我们如何配置 ExpiringUsernameAuthenticationToken 来使用它?如果未设置原始身份验证,为什么会起作用?

为什么应用程序在 IDP 会话过期时尝试重新验证?

WebSSOProfileConsumerImpl 和 SingleLogoutProfileImpl 都提供了设置 responseSkew 的方法。应将其设置为等于、小于还是大于 IDP 的延迟时间?

Spring SAML 默认遵守 IDP 在其 SAML 响应中提供的 SessionNotOnOrAfter 字段。该字段表示一旦时间达到提供的值,用户必须重新进行身份验证。

Spring SAML 尝试通过将当前 Authentication 对象发送到 AuthenticationManager 来重新验证用户,后者会尝试找到支持 [=14= 的 AuhenticationProvier ] 这种类型的对象(ExpiringUsernameAuthenticationToken 在 Spring SAML 的情况下)。在您的情况下,没有这样的提供者 - 这就是您看到 ProviderNotFoundException 异常的原因。发生此错误后 Spring 安全性可能会调用默认值 EntryPoint,它将您的用户重定向到登录页面。

为了忽略 SessionNotOnOrAfter 值,只需扩展 class SAMLAuthenticationProvider,覆盖方法 getExpirationDate 并使其成为 return null。然后在 securityContext.xml.

中使用新的 class

但正确的解决方案是让您的 IDP return SessionNotOnOrAfter 值具有合理的会话长度 - 我想知道他们为什么坚持在那里使用 60 秒。