在 Spring 安全 SAML2 中自定义 OpenSaml4AuthenticationProvider

Customizing OpenSaml4AuthenticationProvider in Spring Security SAML2

我需要使用带有 Spring 安全 SAML2 的遗留 UserDetailsService,所以我正在关注 these instructions from Spring。但是,当我根据该文档尝试将 AuthenticationProvider 替换为所谓的“默认”时出现错误:

public class WigWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
    // I've tried removing these 2 lines and I get the same error
    authenticationProvider.setAssertionValidator(OpenSaml4AuthenticationProvider.createDefaultAssertionValidator());
    authenticationProvider.setResponseAuthenticationConverter(OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter());

    httpSecurity.authorizeRequests(authz -> authz.anyRequest().authenticated())
      .saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)));
  }
}

当我这样做时,我在尝试验证时收到以下错误:

java.lang.NoSuchMethodError: org.opensaml.saml.saml2.assertion.SAML20AssertionValidator.<init>(Ljava/util/Collection;Ljava/util/Collection;Ljava/util/Collection;Lorg/opensaml/saml/saml2/assertion/AssertionValidator;Lorg/opensaml/xmlsec/signature/support/SignatureTrustEngine;Lorg/opensaml/xmlsec/signature/support/SignaturePrevalidator;)V
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider$SAML20AssertionValidators.<init>(OpenSaml4AuthenticationProvider.java:732)
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider$SAML20AssertionValidators.<clinit>(OpenSaml4AuthenticationProvider.java:731)
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.lambda$createDefaultAssertionSignatureValidator(OpenSaml4AuthenticationProvider.java:572)
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.lambda$createAssertionValidator(OpenSaml4AuthenticationProvider.java:654)
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.process(OpenSaml4AuthenticationProvider.java:495)
    at org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.authenticate(OpenSaml4AuthenticationProvider.java:448)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
    at org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter.attemptAuthentication(Saml2WebSsoAuthenticationFilter.java:113)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:222)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)

但是当我使用相同的代码而不设置 authenticationManager 时,SAML 身份验证工作正常。 (任何想要使用我的自定义 UserDetails 的页面当然会失败,因为它没有被填充,但是所有 SAML 身份验证步骤都工作正常。):

public class WigWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {

    httpSecurity.authorizeRequests(authz -> authz.anyRequest().authenticated())
      .saml2Login();
  }
}

原来我用的是org.opensaml:opensaml-api 3.4.6,你要用4.x才能用class OpenSaml4AuthenticationProvider.如果您使用的是 3.x,则需要使用已弃用的 class OpenSamlAuthenticationProvider。我无法升级 opensaml 依赖项,因为我使用的是 Java 8,所以这是适合我的代码:

public class WigWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    // This class is deprecated, but you have to use it if you're using OpenSAML < 4.0
    OpenSamlAuthenticationProvider authenticationProvider = new OpenSamlAuthenticationProvider();
    authenticationProvider.setAssertionValidator(OpenSamlAuthenticationProvider.createDefaultAssertionValidator());
    authenticationProvider.setResponseAuthenticationConverter(OpenSamlAuthenticationProvider.createDefaultResponseAuthenticationConverter());

    httpSecurity.authorizeRequests(authz -> authz.anyRequest().authenticated())
      .saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)));
  }
}

当我发现这就是 Saml2LoginConfigurer 内部所做的事情时,我终于找到了答案。