对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

以下步骤与如何配置 SAML 2.0 的更改相关。Spring中文文档

使用 OpenSAML 4

OpenSAML 3 已达到其生命周期的尽头。 因此,Spring Security 6 放弃了对它的支持,将其 OpenSAML 基线提高到 4。Spring中文文档

要准备升级,请将 pom 更新为依赖于 OpenSAML 4 而不是 3:Spring中文文档

<dependencyManagement>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-core</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-saml-api</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.opensaml</groupId>
        <artifactId>opensaml-saml-impl</artifactId>
        <version>4.2.1</version>
    </dependency>
</dependencyManagement>
dependencies {
    constraints {
        api "org.opensaml:opensaml-core:4.2.1"
        api "org.opensaml:opensaml-saml-api:4.2.1"
        api "org.opensaml:opensaml-saml-impl:4.2.1"
    }
}

您必须至少使用 OpenSAML 4.1.1 才能更新到 Spring Security 6 的 SAML 支持。Spring中文文档

OpenSaml4AuthenticationProvider

为了同时支持 OpenSAML 3 和 4,Spring Security 发布了 和 . 在 6.0 中,由于删除了 OpenSAML3 支持,因此也删除了。OpenSamlAuthenticationProviderOpenSaml4AuthenticationProviderOpenSamlAuthenticationProviderSpring中文文档

并非所有方法都以 1 对 1 的方式移植到 。 因此,需要进行一些调整才能应对挑战。OpenSamlAuthenticationProviderOpenSaml4AuthenticationProviderSpring中文文档

请考虑以下具有代表性的用法:OpenSamlAuthenticationProviderSpring中文文档

OpenSamlAuthenticationProvider versionThree = new OpenSamlAuthenticationProvider();
versionThree.setAuthoritiesExtractor(myAuthoritiesExtractor);
versionThree.setResponseTimeValidationSkew(myDuration);
val versionThree: OpenSamlAuthenticationProvider = OpenSamlAuthenticationProvider()
versionThree.setAuthoritiesExtractor(myAuthoritiesExtractor)
versionThree.setResponseTimeValidationSkew(myDuration)

这应该更改为:Spring中文文档

Converter<ResponseToken, Saml2Authentication> delegate = OpenSaml4AuthenticationProvider
        .createDefaultResponseAuthenticationConverter();
OpenSaml4AuthenticationProvider versionFour = new OpenSaml4AuthenticationProvider();
versionFour.setResponseAuthenticationConverter((responseToken) -> {
	Saml2Authentication authentication = delegate.convert(responseToken);
	Assertion assertion = responseToken.getResponse().getAssertions().get(0);
	AuthenticatedPrincipal principal = (AuthenticatedPrincipal) authentication.getPrincipal();
	Collection<GrantedAuthority> authorities = myAuthoritiesExtractor.convert(assertion);
	return new Saml2Authentication(principal, authentication.getSaml2Response(), authorities);
});
Converter<AssertionToken, Saml2ResponseValidationResult> validator = OpenSaml4AuthenticationProvider
        .createDefaultAssertionValidatorWithParameters((p) -> p.put(CLOCK_SKEW, myDuration));
versionFour.setAssertionValidator(validator);
val delegate = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter()
val versionFour = OpenSaml4AuthenticationProvider()
versionFour.setResponseAuthenticationConverter({
    responseToken -> {
        val authentication = delegate.convert(responseToken)
        val assertion = responseToken.getResponse().getAssertions().get(0)
        val principal = (AuthenticatedPrincipal) authentication.getPrincipal()
        val authorities = myAuthoritiesExtractor.convert(assertion)
        return Saml2Authentication(principal, authentication.getSaml2Response(), authorities)
    }
})
val validator = OpenSaml4AuthenticationProvider
        .createDefaultAssertionValidatorWithParameters({ p -> p.put(CLOCK_SKEW, myDuration) })
versionFour.setAssertionValidator(validator)

停止使用 SAML 2.0 构造函数Converter

在 Spring Security 的 SAML 2.0 支持的早期版本中,并附带了 . 这种抽象级别使得类的发展变得棘手,因此在以后的版本中引入了一个专用接口。Saml2MetadataFilterSaml2AuthenticationTokenConverterConverterRelyingPartyRegistrationResolverSpring中文文档

在 6.0 中,删除了构造函数。 要在 5.8 中为此做好准备,请将 implement(实现)的类更改为 implement。ConverterConverter<HttpServletRequest, RelyingPartyRegistration>RelyingPartyRegistrationResolverSpring中文文档

更改为 使用Saml2AuthenticationRequestResolver

Saml2AuthenticationContextResolver并在 6.0 中删除,因为需要它们。 它们被替换为 和 中的新构造函数。 新接口删除了两个类之间不必要的传输对象。Saml2AuthenticationRequestFactorySaml2WebSsoAuthenticationRequestFilterSaml2AuthenticationRequestResolverSaml2WebSsoAuthenticationRequestFilterSpring中文文档

大多数应用程序不需要执行任何操作;但是,如果您使用 或 配置 或 ,请尝试以下步骤来转换 而不是使用 。Saml2AuthenticationRequestContextResolverSaml2AuthenticationRequestFactorySaml2AuthenticationRequestResolverSpring中文文档

使用代替setAuthnRequestCustomizersetAuthenticationRequestContextConverter

例如,如果您正在调用 ,如下所示:OpenSaml4AuthenticationReqeustFactory#setAuthenticationRequestContextConverterSpring中文文档

@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
    OpenSaml4AuthenticationRequestFactory factory = new OpenSaml4AuthenticationRequestFactory();
	factory.setAuthenticationRequestContextConverter((context) -> {
        AuthnRequestBuilder authnRequestBuilder =  ConfigurationService.get(XMLObjectProviderRegistry.class)
            .getBuilderFactory().getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
		IssuerBuilder issuerBuilder =  ConfigurationService.get(XMLObjectProviderRegistry.class)
            .getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
        tring issuer = context.getIssuer();
		String destination = context.getDestination();
		String assertionConsumerServiceUrl = context.getAssertionConsumerServiceUrl();
		String protocolBinding = context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding().getUrn();
		AuthnRequest auth = authnRequestBuilder.buildObject();
		auth.setID("ARQ" + UUID.randomUUID().toString().substring(1));
		auth.setIssueInstant(Instant.now());
		auth.setForceAuthn(Boolean.TRUE);
		auth.setIsPassive(Boolean.FALSE);
		auth.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
		Issuer iss = issuerBuilder.buildObject();
		iss.setValue(issuer);
		auth.setIssuer(iss);
		auth.setDestination(destination);
		auth.setAssertionConsumerServiceURL(assertionConsumerServiceUrl);
	});
	return factory;
}

若要确保 ForceAuthn 设置为 ,可以改为执行以下操作:trueSpring中文文档

@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationResolver registrations) {
    OpenSaml4AuthenticationRequestResolver reaolver = new OpenSaml4AuthenticationRequestResolver(registrations);
	resolver.setAuthnRequestCustomizer((context) -> context.getAuthnRequest().setForceAuthn(Boolean.TRUE));
	return resolver;
}

此外,由于可以直接访问 ,因此不需要 . 只需直接从您需要的这些信息中读取即可。setAuthnRequestCustomizerHttpServletRequestSaml2AuthenticationRequestContextResolversetAuthnRequestCustomizerHttpServletRequestSpring中文文档

使用代替setAuthnRequestCustomizersetProtocolBinding

而不是做:Spring中文文档

@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
    OpenSaml4AuthenticationRequestFactory factory = new OpenSaml4AuthenticationRequestFactory();
	factory.setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
	return factory;
}

您可以执行以下操作:Spring中文文档

@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver() {
	OpenSaml4AuthenticationRequestResolver reaolver = new OpenSaml4AuthenticationRequestResolver(registrations);
	resolver.setAuthnRequestCustomizer((context) -> context.getAuthnRequest()
            .setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"));
	return resolver;
}

由于 Spring Security 仅支持身份验证绑定,因此此时覆盖协议绑定没有多大价值。POSTSpring中文文档

由于 Spring Security 仅支持身份验证绑定,因此此时覆盖协议绑定没有多大价值。POSTSpring中文文档

使用最新的构造函数Saml2AuthenticationToken

在早期版本中,采用了几个单独的设置作为构造函数参数。 每次需要添加新参数时,这都会带来挑战。 由于这些设置中的大多数都是 的一部分,因此在可以提供 的地方添加了一个新的构造函数,使构造函数更加稳定。 它的价值还在于它与 的设计更紧密地保持一致。Saml2AuthenticationTokenRelyingPartyRegistrationRelyingPartyRegistrationOAuth2LoginAuthenticationTokenSpring中文文档

大多数应用程序不直接构造此类,因为确实如此。 但是,如果您的应用程序构造了一个,请从以下位置更改为:Saml2WebSsoAuthenticationFilterSpring中文文档

new Saml2AuthenticationToken(saml2Response, registration.getSingleSignOnServiceLocation(),
    registration.getAssertingParty().getEntityId(), registration.getEntityId(), registration.getCredentials())
Saml2AuthenticationToken(saml2Response, registration.getSingleSignOnServiceLocation(),
    registration.getAssertingParty().getEntityId(), registration.getEntityId(), registration.getCredentials())
new Saml2AuthenticationToken(saml2Response, registration)
Saml2AuthenticationToken(saml2Response, registration)

使用更新的方法RelyingPartyRegistration

在 Spring Security 的 SAML 支持的早期版本中,某些方法的含义及其功能存在一些模糊性。 随着更多功能的加入,有必要通过将方法名称更改为与规范语言一致的方法名称来澄清这种歧义。RelyingPartyRegistrationRelyingPartyRegistrationSpring中文文档

中已弃用的方法将被删除。 为此,请考虑以下代表性用法:RelyingPartyRegstrationRelyingPartyRegistrationSpring中文文档

String idpEntityId = registration.getRemoteIdpEntityId();
String assertionConsumerServiceUrl = registration.getAssertionConsumerServiceUrlTemplate();
String idpWebSsoUrl = registration.getIdpWebSsoUrl();
String localEntityId = registration.getLocalEntityIdTemplate();
List<Saml2X509Credential> verifying = registration.getCredentials().stream()
        .filter(Saml2X509Credential::isSignatureVerficationCredential)
        .collect(Collectors.toList());
val idpEntityId: String = registration.getRemoteIdpEntityId()
val assertionConsumerServiceUrl: String = registration.getAssertionConsumerServiceUrlTemplate()
val idpWebSsoUrl: String = registration.getIdpWebSsoUrl()
val localEntityId: String = registration.getLocalEntityIdTemplate()
val verifying: List<Saml2X509Credential> = registration.getCredentials()
        .filter(Saml2X509Credential::isSignatureVerficationCredential)

这应该更改为:Spring中文文档

String assertingPartyEntityId = registration.getAssertingPartyDetails().getEntityId();
String assertionConsumerServiceLocation = registration.getAssertionConsumerServiceLocation();
String singleSignOnServiceLocation = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation();
String entityId = registration.getEntityId();
List<Saml2X509Credential> verifying = registration.getAssertingPartyDetails().getVerificationX509Credentials();
val assertingPartyEntityId: String = registration.getAssertingPartyDetails().getEntityId()
val assertionConsumerServiceLocation: String = registration.getAssertionConsumerServiceLocation()
val singleSignOnServiceLocation: String = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation()
val entityId: String = registration.getEntityId()
val verifying: List<Saml2X509Credential> = registration.getAssertingPartyDetails().getVerificationX509Credentials()

有关所有更改方法的完整列表,请参阅 RelyingPartyRegistration 的 JavaDocSpring中文文档