Producing `<saml2:AuthnRequest>`s

如前所述,Spring Security 的 SAML 2.0 支持会产生 <saml2:AuthnRequest> 以开始与声明方的验证。 Spring Security 部分通过在过滤器链中注册 Saml2WebSsoAuthenticationRequestFilter 来实现这一点。该过滤器默认对 /saml2/authenticate/{registrationId} 终端节点做出响应。 例如,如果您已部署到 https://rp.example.com 并且您的注册 ID 为 okta,您可以导航到: https://rp.example.org/saml2/authenticate/okta 结果将是重定向,其中包含一个 SAMLRequest 参数,该参数包含已签名、已压缩和已编码的 <saml2:AuthnRequest>

Changing How the <saml2:AuthnRequest> Gets Stored

Saml2WebSsoAuthenticationRequestFilter 使用 Saml2AuthenticationRequestRepositorysending the <saml2:AuthnRequest> 之前将 AbstractSaml2AuthenticationRequest 实例持久化到声明方。

此外,Saml2WebSsoAuthenticationFilterSaml2AuthenticationTokenConverter 使用 Saml2AuthenticationRequestRepository 加载所有 AbstractSaml2AuthenticationRequest 作为 authenticating the <saml2:Response> 的一部分。

默认情况下,Spring Security 使用 HttpSessionSaml2AuthenticationRequestRepository,它存储在 HttpSession 中的 AbstractSaml2AuthenticationRequest

如果您有 Saml2AuthenticationRequestRepository 的自定义实现,您可以通过将其公开为 @Bean 来配置它,如下例所示:

  • Java

  • Kotlin

@Bean
Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository() {
	return new CustomSaml2AuthenticationRequestRepository();
}
@Bean
open fun authenticationRequestRepository(): Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> {
    return CustomSaml2AuthenticationRequestRepository()
}

Changing How the <saml2:AuthnRequest> Gets Sent

默认情况下,Spring Security 签署每个 <saml2:AuthnRequest> 并作为 GET 发送到声明方。

许多声明方不需要签名的 <saml2:AuthnRequest>。这可以通过 RelyingPartyRegistrations 自动配置,或者您可以手动提供,如下所示:

Not Requiring Signed AuthnRequests
  • Boot

  • Java

  • Kotlin

spring:
  security:
    saml2:
      relyingparty:
        okta:
          identityprovider:
            entity-id: ...
            singlesignon.sign-request: false
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
        // ...
        .assertingPartyDetails(party -> party
            // ...
            .wantAuthnRequestsSigned(false)
        )
        .build();
var relyingPartyRegistration: RelyingPartyRegistration =
    RelyingPartyRegistration.withRegistrationId("okta")
        // ...
        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
                // ...
                .wantAuthnRequestsSigned(false)
        }
        .build();

否则,您需要为 RelyingPartyRegistration#signingX509Credentials 指定一个私钥,以便 Spring Security 在发送之前签署 <saml2:AuthnRequest>

默认情况下,Spring Security 将使用 rsa-sha256 签名 <saml2:AuthnRequest>,尽管某些声明方需要不同的算法,如其元数据中所示。

您可以基于声明方的 metadata using RelyingPartyRegistrations 配置算法。

或者,可以手动提供它:

  • Java

  • Kotlin

String metadataLocation = "classpath:asserting-party-metadata.xml";
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
        // ...
        .assertingPartyDetails((party) -> party
            // ...
            .signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512))
        )
        .build();
var metadataLocation = "classpath:asserting-party-metadata.xml"
var relyingPartyRegistration: RelyingPartyRegistration =
    RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
        // ...
        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
                // ...
                .signingAlgorithms { sign: MutableList<String?> ->
                    sign.add(
                        SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512
                    )
                }
        }
        .build();

上面的代码片段使用 OpenSAML SignatureConstants 类来提供算法名称。但这只是为了方便。由于数据类型为 String,您可以直接提供算法名称。

某些声明方要求提交 <saml2:AuthnRequest>。这可以通过 RelyingPartyRegistrations 自动配置,也可以手动提供它,如下所示:

  • Java

  • Kotlin

RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
        // ...
        .assertingPartyDetails(party -> party
            // ...
            .singleSignOnServiceBinding(Saml2MessageBinding.POST)
        )
        .build();
var relyingPartyRegistration: RelyingPartyRegistration? =
    RelyingPartyRegistration.withRegistrationId("okta")
        // ...
        .assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
            // ...
            .singleSignOnServiceBinding(Saml2MessageBinding.POST)
        }
        .build()

Customizing OpenSAML’s AuthnRequest Instance

有很多理由需要调整 AuthnRequest。例如,您可能希望 ForceAuthN 设置为 true,Spring Security 默认将其设置为 false

可以通过发布一个 OpenSaml4AuthenticationRequestResolver 作为 @Bean 来自定义 OpenSAML 的 AuthnRequest 元素,如下所示:

  • Java

  • Kotlin

@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
    RelyingPartyRegistrationResolver registrationResolver =
            new DefaultRelyingPartyRegistrationResolver(registrations);
    OpenSaml4AuthenticationRequestResolver authenticationRequestResolver =
            new OpenSaml4AuthenticationRequestResolver(registrationResolver);
    authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
            .getAuthnRequest().setForceAuthn(true));
    return authenticationRequestResolver;
}
@Bean
fun authenticationRequestResolver(registrations : RelyingPartyRegistrationRepository) : Saml2AuthenticationRequestResolver {
    val registrationResolver : RelyingPartyRegistrationResolver =
            new DefaultRelyingPartyRegistrationResolver(registrations)
    val authenticationRequestResolver : OpenSaml4AuthenticationRequestResolver =
            new OpenSaml4AuthenticationRequestResolver(registrationResolver)
    authenticationRequestResolver.setAuthnRequestCustomizer((context) -> context
            .getAuthnRequest().setForceAuthn(true))
    return authenticationRequestResolver
}