我正在将Spring SAML添加到某些软件,直到现在,这些软件仅使用OAuth2。我需要确保OAuth仍然有效,因为SAML仅适用于某些客户。
我遇到了一个旧的oAuth似乎不再起作用的问题(尽管SAML基本上可以)。似乎认证管理器正在以某种方式被覆盖,但尚不清楚如何或为什么。这是我的WebSecurityConfig.java中的相关代码:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordService.getEncoder())
.and()
.authenticationProvider(samlAuthenticationProvider)
.authenticationProvider(oAuth2AuthenticationProvider());
}
和SAMLConfig.java:
@Bean
public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception {
SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter();
samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager());
samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler());
samlWebSSOProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return samlWebSSOProcessingFilter;
}
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(samlAuthenticationProvider()));
}
显然,这是错误的,但是尚不清楚如何纠正它。
当我调试时,在启动时会调用AuthenticationManagerBuilder.performBuild()3次。
第一次使用SAML,OAuth2和Dao AuthenticationProviders构建一个。
第二个用AnonymousAuthenticationProvider构建一个。
第三,与另一个DaoAuthenticationProvider建立一个。
登录时,ProviderManager.authenticate()被调用两次。
第一次,它只有一个提供程序AnonymousAuthenticationProvider。这不进行身份验证。
第二次是第一次的父级经理。它只有一个提供程序SAMLAuthenticationProvider。如果在SAML中找不到与我进行身份验证的用户,则该用户仍然是最后一个被调用的提供者或管理者。
为什么?如何更正此错误,以便我可以在某些情况下将凭据定向到SAML,在所有其他情况下将OAuth引导,或者允许在SAML中不起作用的任何凭据溢出到OAuth?
最佳答案
new ProviderManager()
创建一个AuthenticationManager来跳过构建器过程,这就是为什么在调试performBuild()
时不显示它的原因。authenticationManager()
bean方法旨在返回现有的全局AuthenticationManager,但是问题使用它的方式而是返回一个新的不同的AuthenticationManager,从而覆盖了构建器返回的内容。这就是为什么在调试authenticate()
时会显示它,而内置的AuthenticationManager却不显示的原因。
解决方案是将现有的AuthenticationManager传递给SAMLProcessingFilter.setAuthenticationManager()
,而不是新的。我这样做的方法是将所有代码从SAMLConfig.java移到WebSecurityConfig.java,这更简单,但这并不是唯一的方法。