此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.1spring-doc.cn

SAML 迁移

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

使用 OpenSAML 4

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

要准备升级,请将 pom 更新为依赖于 OpenSAML 4 而不是 3:spring-doc.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.cn

OpenSaml4AuthenticationProvider

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

并非所有 中的方法都以 1 对 1 的方式移植到 。 因此,需要进行一些调整才能进行挑战。OpenSamlAuthenticationProviderOpenSaml4AuthenticationProviderspring-doc.cn

请考虑以下 的代表性用法:OpenSamlAuthenticationProviderspring-doc.cn

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

这应该更改为:spring-doc.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.0 构造函数Converter

在 Spring Security 的 SAML 2.0 支持的早期版本中,并附带了 . 这种抽象级别使得类的演化变得很棘手,因此在以后的版本中引入了专用接口。Saml2MetadataFilterSaml2AuthenticationTokenConverterConverterRelyingPartyRegistrationResolverspring-doc.cn

在 6.0 中,构造函数被删除。 要在 5.8 中为此做好准备,请将 implement 的类更改为 implement 。ConverterConverter<HttpServletRequest, RelyingPartyRegistration>RelyingPartyRegistrationResolverspring-doc.cn

更改为使用Saml2AuthenticationRequestResolver

Saml2AuthenticationContextResolver并在 6.0 中删除,就像需要它们一样。 它们被 和 中的新构造函数替换。 新接口删除了两个类之间不必要的传输对象。Saml2AuthenticationRequestFactorySaml2WebSsoAuthenticationRequestFilterSaml2AuthenticationRequestResolverSaml2WebSsoAuthenticationRequestFilterspring-doc.cn

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

使用而不是setAuthnRequestCustomizersetAuthenticationRequestContextConverter

例如,如果您正在调用 ,则如下所示:OpenSaml4AuthenticationReqeustFactory#setAuthenticationRequestContextConverterspring-doc.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 设置为 ,您可以改为执行以下操作:truespring-doc.cn

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

此外,由于可以直接访问 ,因此不需要 . 只需使用 直接从您需要的此信息中读取。setAuthnRequestCustomizerHttpServletRequestSaml2AuthenticationRequestContextResolversetAuthnRequestCustomizerHttpServletRequestspring-doc.cn

使用而不是setAuthnRequestCustomizersetProtocolBinding

而不是执行:spring-doc.cn

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

您可以执行以下操作:spring-doc.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 仅支持用于身份验证的绑定,因此此时覆盖协议绑定没有太大价值。POSTspring-doc.cn

使用最新的构造函数Saml2AuthenticationToken

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

大多数应用程序不会直接构造此类,因为会。 但是,如果您的应用程序构造了一个,请从以下位置更改:Saml2WebSsoAuthenticationFilterspring-doc.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 支持的早期版本中,某些方法的含义及其功能存在一些歧义。 随着 中添加了更多功能,有必要通过将方法名称更改为与 spec 语言一致的名称来澄清这种歧义。RelyingPartyRegistrationRelyingPartyRegistrationspring-doc.cn

中已弃用的方法将被删除。 为此,请考虑以下 的代表性用法 :RelyingPartyRegstrationRelyingPartyRegistrationspring-doc.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.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 的 JavaDocspring-doc.cn