Saml 2.0 元数据
Spring Security 可以解析身份认证方元数据 以生成 AssertingPartyMetadata
实例,以及从 RelyingPartyRegistration
实例发布依赖方元数据。
解析 <saml2:IDPSSODescriptor>
元数据
您可以解析身份认证方的元数据使用 RelyingPartyRegistrations。
当使用 OpenSAML 供应商支持时,生成的 AssertingPartyMetadata
将是 OpenSamlAssertingPartyDetails
类型。这意味着你可以通过以下方式获取底层的 OpenSAML XMLObject:
- Java
- Kotlin
OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails)
registration.getAssertingPartyMetadata();
EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor();
val details: OpenSamlAssertingPartyDetails =
registration.getAssertingPartyMetadata() as OpenSamlAssertingPartyDetails
val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor()
使用 AssertingPartyMetadataRepository
您还可以通过使用 AssertingPartyMetadataRepository
来比 RelyingPartyRegistrations
更有针对性,这是一个仅允许检索断言方元数据的接口。
这允许三个有价值的功能:
-
实现可以以一种过期感知的方式刷新断言方元数据
-
RelyingPartyRegistrationRepository
的实现可以更轻松地表达依赖方与其一个或多个相应的断言方之间的关系 -
实现可以验证元数据签名
例如,OpenSaml4AssertingPartyMetadataRepository
使用 OpenSAML 的 MetadataResolver
,该 API 的实现会以一种过期感知的方式定期刷新底层的元数据。
这意味着你现在只需几行代码就可以创建一个可刷新的 RelyingPartyRegistrationRepository
:
- Java
- Kotlin
@Component
public class RefreshableRelyingPartyRegistrationRepository
implements IterableRelyingPartyRegistrationRepository {
private final AssertingPartyMetadataRepository metadata =
OpenSamlAssertingPartyMetadataRepository
.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 =
OpenSamlAssertingPartyMetadataRepository.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()
}
}
OpenSaml4AssertingPartyMetadataRepository
还提供了一个构造函数,因此你可以提供一个自定义的 MetadataResolver
。由于底层的 MetadataResolver
负责过期和刷新,如果你直接使用构造函数,只有在提供了一个实现这些功能的实现类时,你才能获得这些功能。
验证元数据签名
您还可以通过提供适当的 Saml2X509Credential
集合来使用 OpenSaml4AssertingPartyMetadataRepository
验证元数据签名,如下所示:
- Java
- Kotlin
OpenSamlAssertingPartyMetadataRepository.withMetadataLocation("https://idp.example.org/metadata")
.verificationCredentials((c) -> c.add(myVerificationCredential))
.build();
OpenSamlAssertingPartyMetadataRepository.withMetadataLocation("https://idp.example.org/metadata")
.verificationCredentials({ c : Collection<Saml2X509Credential> ->
c.add(myVerificationCredential) })
.build()
如果未提供凭证,组件将不会执行签名验证。
生成 <saml2:SPSSODescriptor>
元数据
你可以使用 saml2Metadata
DSL 方法发布元数据端点,如下所示:
- Java
- Kotlin
http
// ...
.saml2Login(withDefaults())
.saml2Metadata(withDefaults());
http {
//...
saml2Login { }
saml2Metadata { }
}
您可以使用此元数据端点将您的依赖方注册到您的认证方。这通常只需要找到正确的表单字段来提供元数据端点即可。
默认情况下,元数据端点是 /saml2/metadata
,不过它也响应 /saml2/metadata/{registrationId}
和 /saml2/service-provider-metadata/{registrationId}
。
您可以通过在DSL中调用metadataUrl
方法来更改这一点:
- Java
- Kotlin
.saml2Metadata((saml2) -> saml2.metadataUrl("/saml/metadata"))
saml2Metadata {
metadataUrl = "/saml/metadata"
}
更改查找 RelyingPartyRegistration
的方式
如果你有其他策略来确定使用哪个 RelyingPartyRegistration
,你可以配置自己的 Saml2MetadataResponseResolver
,如下所示:
- Java
- Kotlin
@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
}