对于最新的稳定版本,请使用 Spring Security 6.4.3spring-doc.cadn.net.cn

SAML 迁移

以下步骤与有关如何配置 SAML 2.0 的更改有关。spring-doc.cadn.net.cn

使用 OpenSAML 4

OpenSAML 3 的生命周期已结束。 因此,Spring Security 6 放弃了对它的支持,将其 OpenSAML 基线提高到 4。spring-doc.cadn.net.cn

要准备升级,请将 pom 更新为依赖于 OpenSAML 4 而不是 3:spring-doc.cadn.net.cn

<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-doc.cadn.net.cn

OpenSaml4AuthenticationProvider

为了同时支持 OpenSAML 3 和 OpenSAML 4,Spring Security 发布了OpenSamlAuthenticationProviderOpenSaml4AuthenticationProvider. 在 6.0 中,由于删除了 OpenSAML3 支持,因此OpenSamlAuthenticationProvider也会被删除。spring-doc.cadn.net.cn

并非 中的所有方法OpenSamlAuthenticationProvider被 1 对 1 移植到OpenSaml4AuthenticationProvider. 因此,需要进行一些调整才能进行挑战。spring-doc.cadn.net.cn

考虑以下OpenSamlAuthenticationProvider:spring-doc.cadn.net.cn

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

这应该更改为:spring-doc.cadn.net.cn

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.0Converter构造 函数

在 Spring Security 的 SAML 2.0 支持的早期版本中,Saml2MetadataFilterSaml2AuthenticationTokenConverterConverter. 这种抽象级别使得发展类变得很棘手,因此需要一个专用的接口RelyingPartyRegistrationResolver在更高版本中引入。spring-doc.cadn.net.cn

在 6.0 中,Converter构造函数被删除。 要在 5.8 中为此做好准备,请更改实现Converter<HttpServletRequest, RelyingPartyRegistration>改为实现RelyingPartyRegistrationResolver.spring-doc.cadn.net.cn

更改为使用Saml2AuthenticationRequestResolver

Saml2AuthenticationContextResolverSaml2AuthenticationRequestFactory在 6.0 中删除,就像Saml2WebSsoAuthenticationRequestFilter这需要他们。 它们被替换为Saml2AuthenticationRequestResolver和一个新的构造函数Saml2WebSsoAuthenticationRequestFilter. 新接口删除了两个类之间不必要的传输对象。spring-doc.cadn.net.cn

大多数应用程序不需要执行任何作;但是,如果您使用或配置Saml2AuthenticationRequestContextResolverSaml2AuthenticationRequestFactory,请尝试以下步骤来转换,而不是使用Saml2AuthenticationRequestResolver.spring-doc.cadn.net.cn

setAuthnRequestCustomizer而不是setAuthenticationRequestContextConverter

如果您正在调用OpenSaml4AuthenticationReqeustFactory#setAuthenticationRequestContextConverter,例如:spring-doc.cadn.net.cn

@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 设置为true,您可以改为执行以下作:spring-doc.cadn.net.cn

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

此外,由于setAuthnRequestCustomizer可以直接访问HttpServletRequest,则不需要Saml2AuthenticationRequestContextResolver. 简单使用setAuthnRequestCustomizer直接从HttpServletRequest您需要的此信息。spring-doc.cadn.net.cn

setAuthnRequestCustomizer而不是setProtocolBinding

而不是执行:spring-doc.cadn.net.cn

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

您可以执行以下作:spring-doc.cadn.net.cn

@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 仅支持POSTbinding 进行身份验证时,此时覆盖协议绑定没有太大价值。spring-doc.cadn.net.cn

使用最新的Saml2AuthenticationToken构造 函数

在早期版本中,Saml2AuthenticationToken将几个单独的设置作为构造函数参数。 每次需要添加新参数时,这都会带来挑战。 由于这些设置中的大多数都是RelyingPartyRegistration中,添加了一个新的构造函数,其中RelyingPartyRegistration,使构造函数更稳定。 它还在于它与OAuth2LoginAuthenticationToken.spring-doc.cadn.net.cn

大多数应用程序不会直接构造此类,因为Saml2WebSsoAuthenticationFilter确实。 但是,如果您的应用程序构造了一个,请从以下位置更改:spring-doc.cadn.net.cn

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 支持的早期版本中,某些RelyingPartyRegistration方法及其功能。 随着更多功能的添加RelyingPartyRegistration,有必要通过将方法名称更改为与 spec 语言一致的名称来澄清这种歧义。spring-doc.cadn.net.cn

中已弃用的方法RelyingPartyRegstration被删除。 为此,请考虑以下RelyingPartyRegistration:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

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的 JavaDoc.spring-doc.cadn.net.cn