SAML 2.0 元数据
解析<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
你也可以比使用 RelyingPartyRegistrations 更加精准,方法是使用 AssertingPartyMetadataRepository 接口,该接口仅用于获取断言方元数据。
这提供了三个宝贵的功能:
-
实现可以以感知过期的方式刷新断言方元数据
-
RelyingPartyRegistrationRepository的实现可以更清晰地表达依赖方与其一个或多个对应断言方之间的关系。 -
实现类可以验证元数据签名
例如,OpenSaml5AssertingPartyMetadataRepository 使用 OpenSAML 的 MetadataResolver,该 API 的实现会以感知过期的方式定期刷新底层元数据。
这意味着你现在只需几行代码即可创建一个可刷新的RelyingPartyRegistrationRepository:
-
Java
-
Kotlin
@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 来验证元数据签名,如下所示:
-
Java
-
Kotlin
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 方法发布一个元数据端点,如下所示:
-
Java
-
Kotlin
http
// ...
.saml2Login(withDefaults())
.saml2Metadata(withDefaults());
http {
//...
saml2Login { }
saml2Metadata { }
}
您可以使用此元数据端点将您的依赖方(Relying Party)注册到您的断言方(Asserting Party)。 通常,这只需找到正确的表单字段并提供该元数据端点即可。
默认情况下,元数据端点为 /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
}