此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Security 7.0.4spring-doc.cadn.net.cn

SAML 2.0 元数据

Spring Security 可以解析断言方元数据以生成一个 AssertingPartyMetadata 实例,也可以从 #publishing-relying-party-metadata 实例发布信赖方元数据spring-doc.cadn.net.cn

解析<saml2:IDPSSODescriptor>元数据

您可以使用RelyingPartyRegistrations解析断言方的元数据。spring-doc.cadn.net.cn

使用 OpenSAML 提供商支持时,生成的 AssertingPartyMetadata 将是 OpenSamlAssertingPartyDetails 类型。 这意味着您可以通过以下方式获取底层的 OpenSAML XMLObject:spring-doc.cadn.net.cn

OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails)
        registration.getAssertingPartyMetadata();
EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor();
val details: OpenSamlAssertingPartyDetails =
        registration.getAssertingPartyMetadata() as OpenSamlAssertingPartyDetails
val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor()

使用AssertingPartyMetadataRepository

你也可以比使用 RelyingPartyRegistrations 更加精准,方法是使用 AssertingPartyMetadataRepository 接口,该接口仅用于获取断言方元数据。spring-doc.cadn.net.cn

这提供了三个宝贵的功能:spring-doc.cadn.net.cn

例如,OpenSaml5AssertingPartyMetadataRepository 使用 OpenSAML 的 MetadataResolver,该 API 的实现会以感知过期的方式定期刷新底层元数据。spring-doc.cadn.net.cn

这意味着你现在只需几行代码即可创建一个可刷新的RelyingPartyRegistrationRepositoryspring-doc.cadn.net.cn

@Component
public class RefreshableRelyingPartyRegistrationRepository
        implements IterableRelyingPartyRegistrationRepository {

	private final AssertingPartyMetadataRepository metadata =
            OpenSaml5AssertingPartyMetadataRepository
                .fromTrustedMetadataLocation("https://idp.example.org/metadata").build();

	@Override
    public RelyingPartyRegistration findByRegistrationId(String registrationId) {
		AssertingPartyMetadata metadata = this.metadata.findByEntityId(registrationId);
        if (metadata == null) {
            return null;
        }
		return applyRelyingParty(metadata);
    }

	@Override
    public Iterator<RelyingPartyRegistration> iterator() {
		return StreamSupport.stream(this.metadata.spliterator(), false)
            .map(this::applyRelyingParty).iterator();
    }

	private RelyingPartyRegistration applyRelyingParty(AssertingPartyMetadata metadata) {
		return RelyingPartyRegistration.withAssertingPartyMetadata(metadata)
            // apply any relying party configuration
            .build();
	}

}
@Component
class RefreshableRelyingPartyRegistrationRepository : IterableRelyingPartyRegistrationRepository {

    private val metadata: AssertingPartyMetadataRepository =
        OpenSaml5AssertingPartyMetadataRepository.fromTrustedMetadataLocation(
            "https://idp.example.org/metadata").build()

    fun findByRegistrationId(registrationId:String?): RelyingPartyRegistration {
        val metadata = this.metadata.findByEntityId(registrationId)
        if (metadata == null) {
            return null
        }
        return applyRelyingParty(metadata)
    }

    fun iterator(): Iterator<RelyingPartyRegistration> {
        return StreamSupport.stream(this.metadata.spliterator(), false)
            .map(this::applyRelyingParty).iterator()
    }

    private fun applyRelyingParty(metadata: AssertingPartyMetadata): RelyingPartyRegistration {
        val details: AssertingPartyMetadata = metadata as AssertingPartyMetadata
        return RelyingPartyRegistration.withAssertingPartyMetadata(details)
            // apply any relying party configuration
            .build()
    }
 }
OpenSaml5AssertingPartyMetadataRepository 还提供了一个构造函数,以便你可以传入自定义的 MetadataResolver。由于底层的 MetadataResolver 负责过期和刷新操作,如果你直接使用该构造函数,则只有在你提供的实现本身支持这些功能时,才能获得过期和刷新特性。

验证元数据签名

您还可以通过提供适当的 OpenSaml5AssertingPartyMetadataRepository 凭据集,使用 Saml2X509Credential 来验证元数据签名,如下所示:spring-doc.cadn.net.cn

OpenSaml5AssertingPartyMetadataRepository.withMetadataLocation("https://idp.example.org/metadata")
    .verificationCredentials((c) -> c.add(myVerificationCredential))
    .build();
OpenSaml5AssertingPartyMetadataRepository.withMetadataLocation("https://idp.example.org/metadata")
    .verificationCredentials({ c : Collection<Saml2X509Credential> ->
        c.add(myVerificationCredential) })
    .build()
如果未提供凭据,该组件将不会执行签名验证。

生产<saml2:SPSSODescriptor>元数据

您可以使用 saml2Metadata DSL 方法发布一个元数据端点,如下所示:spring-doc.cadn.net.cn

http
    // ...
    .saml2Login(withDefaults())
    .saml2Metadata(withDefaults());
http {
    //...
    saml2Login { }
    saml2Metadata { }
}

您可以使用此元数据端点将您的依赖方(Relying Party)注册到您的断言方(Asserting Party)。 通常,这只需找到正确的表单字段并提供该元数据端点即可。spring-doc.cadn.net.cn

默认情况下,元数据端点为 /saml2/metadata,但它也响应 /saml2/metadata/{registrationId}/saml2/service-provider-metadata/{registrationId}spring-doc.cadn.net.cn

你可以通过在 DSL 中调用 metadataUrl 方法来更改此项:spring-doc.cadn.net.cn

.saml2Metadata((saml2) -> saml2.metadataUrl("/saml/metadata"))
saml2Metadata {
	metadataUrl = "/saml/metadata"
}

改变RelyingPartyRegistration被查找

如果你有不同的策略来确定应使用哪个 RelyingPartyRegistration,你可以像下面这样配置自己的 Saml2MetadataResponseResolverspring-doc.cadn.net.cn

@Bean
Saml2MetadataResponseResolver metadataResponseResolver(RelyingPartyRegistrationRepository registrations) {
	RequestMatcherMetadataResponseResolver metadata = new RequestMatcherMetadataResponseResolver(
			(id) -> registrations.findByRegistrationId("relying-party"));
	metadata.setMetadataFilename("metadata.xml");
	return metadata;
}
@Bean
fun metadataResponseResolver(val registrations: RelyingPartyRegistrationRepository): Saml2MetadataResponseResolver {
    val metadata = new RequestMatcherMetadataResponseResolver(
			id: String -> registrations.findByRegistrationId("relying-party"))
	metadata.setMetadataFilename("metadata.xml")
	return metadata
}