Skip to content

Commit

Permalink
Use AssertingPartyMetadata
Browse files Browse the repository at this point in the history
Issue gh-15394
  • Loading branch information
jzheaux committed Jul 20, 2024
1 parent f9d5dda commit 6a5eb3b
Show file tree
Hide file tree
Showing 29 changed files with 320 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
Expand Down Expand Up @@ -153,7 +154,7 @@ private static Map<String, Map<String, Object>> getAssertingParties(Element elem
}

private static void addVerificationCredentials(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
AssertingPartyMetadata.Builder<?> builder) {
List<String> verificationCertificateLocations = (List<String>) assertingParty.get(ELT_VERIFICATION_CREDENTIAL);
List<Saml2X509Credential> verificationCredentials = new ArrayList<>();
for (String certificateLocation : verificationCertificateLocations) {
Expand All @@ -163,7 +164,7 @@ private static void addVerificationCredentials(Map<String, Object> assertingPart
}

private static void addEncryptionCredentials(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
AssertingPartyMetadata.Builder<?> builder) {
List<String> encryptionCertificateLocations = (List<String>) assertingParty.get(ELT_ENCRYPTION_CREDENTIAL);
List<Saml2X509Credential> encryptionCredentials = new ArrayList<>();
for (String certificateLocation : encryptionCertificateLocations) {
Expand Down Expand Up @@ -220,8 +221,8 @@ private static RelyingPartyRegistration.Builder getBuilderFromMetadataLocationIf
}
else {
builder = RelyingPartyRegistration.withRegistrationId(registrationId)
.assertingPartyDetails((apBuilder) -> buildAssertingParty(relyingPartyRegistrationElt, assertingParties,
apBuilder, parserContext));
.assertingPartyMetadata((apBuilder) -> buildAssertingParty(relyingPartyRegistrationElt,
assertingParties, apBuilder, parserContext));
}
addRemainingProperties(relyingPartyRegistrationElt, builder);
return builder;
Expand Down Expand Up @@ -260,7 +261,7 @@ private static void addRemainingProperties(Element relyingPartyRegistrationElt,
}

private static void buildAssertingParty(Element relyingPartyElt, Map<String, Map<String, Object>> assertingParties,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder, ParserContext parserContext) {
AssertingPartyMetadata.Builder<?> builder, ParserContext parserContext) {
String assertingPartyId = relyingPartyElt.getAttribute(ATT_ASSERTING_PARTY_ID);
if (!assertingParties.containsKey(assertingPartyId)) {
Object source = parserContext.extractSource(relyingPartyElt);
Expand Down Expand Up @@ -293,7 +294,7 @@ private static void buildAssertingParty(Element relyingPartyElt, Map<String, Map
}

private static void addSigningAlgorithms(Map<String, Object> assertingParty,
RelyingPartyRegistration.AssertingPartyDetails.Builder builder) {
AssertingPartyMetadata.Builder<?> builder) {
String signingAlgorithmsAttr = getAsString(assertingParty, ATT_SIGNING_ALGORITHMS);
if (StringUtils.hasText(signingAlgorithmsAttr)) {
List<String> signingAlgorithms = Arrays.asList(signingAlgorithmsAttr.split(","));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Java::
----
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails(party -> party
.assertingPartyMetadata(party -> party
// ...
.wantAuthnRequestsSigned(false)
)
Expand All @@ -128,7 +128,7 @@ Kotlin::
var relyingPartyRegistration: RelyingPartyRegistration =
RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
.assertingPartyMetadata { party: AssertingPartyMetadata.Builder -> party
// ...
.wantAuthnRequestsSigned(false)
}
Expand All @@ -154,7 +154,7 @@ Java::
String metadataLocation = "classpath:asserting-party-metadata.xml";
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
// ...
.assertingPartyDetails((party) -> party
.assertingPartyMetadata((party) -> party
// ...
.signingAlgorithms((sign) -> sign.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512))
)
Expand All @@ -169,7 +169,7 @@ var metadataLocation = "classpath:asserting-party-metadata.xml"
var relyingPartyRegistration: RelyingPartyRegistration =
RelyingPartyRegistrations.fromMetadataLocation(metadataLocation)
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
.assertingPartyMetadata { party: AssertingPartyMetadata.Builder -> party
// ...
.signingAlgorithms { sign: MutableList<String?> ->
sign.add(
Expand Down Expand Up @@ -197,7 +197,7 @@ Java::
----
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails(party -> party
.assertingPartyMetadata(party -> party
// ...
.singleSignOnServiceBinding(Saml2MessageBinding.POST)
)
Expand All @@ -211,7 +211,7 @@ Kotlin::
var relyingPartyRegistration: RelyingPartyRegistration? =
RelyingPartyRegistration.withRegistrationId("okta")
// ...
.assertingPartyDetails { party: AssertingPartyDetails.Builder -> party
.assertingPartyMetadata { party: AssertingPartyMetadata.Builder -> party
// ...
.singleSignOnServiceBinding(Saml2MessageBinding.POST)
}
Expand Down
10 changes: 5 additions & 5 deletions docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exc
Saml2X509Credential credential = Saml2X509Credential.verification(certificate);
RelyingPartyRegistration registration = RelyingPartyRegistration
.withRegistrationId("example")
.assertingPartyDetails(party -> party
.assertingPartyMetadata(party -> party
.entityId("https://idp.example.com/issuer")
.singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
.wantAuthnRequestsSigned(false)
Expand All @@ -508,7 +508,7 @@ open fun relyingPartyRegistrations(): RelyingPartyRegistrationRepository {
val credential: Saml2X509Credential = Saml2X509Credential.verification(certificate)
val registration = RelyingPartyRegistration
.withRegistrationId("example")
.assertingPartyDetails { party: AssertingPartyDetails.Builder ->
.assertingPartyMetadata { party: AssertingPartyMetadata.Builder ->
party
.entityId("https://idp.example.com/issuer")
.singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
Expand Down Expand Up @@ -699,7 +699,7 @@ RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.wit
.entityId("{baseUrl}/{registrationId}")
.decryptionX509Credentials(c -> c.add(relyingPartyDecryptingCredential()))
.assertionConsumerServiceLocation("/my-login-endpoint/{registrationId}")
.assertingPartyDetails(party -> party
.assertingPartyMetadata(party -> party
.entityId("https://ap.example.org")
.verificationX509Credentials(c -> c.add(assertingPartyVerifyingCredential()))
.singleSignOnServiceLocation("https://ap.example.org/SSO.saml2")
Expand All @@ -718,7 +718,7 @@ val relyingPartyRegistration =
c.add(relyingPartyDecryptingCredential())
}
.assertionConsumerServiceLocation("/my-login-endpoint/{registrationId}")
.assertingPartyDetails { party -> party
.assertingPartyMetadata { party -> party
.entityId("https://ap.example.org")
.verificationX509Credentials { c -> c.add(assertingPartyVerifyingCredential()) }
.singleSignOnServiceLocation("https://ap.example.org/SSO.saml2")
Expand All @@ -730,7 +730,7 @@ val relyingPartyRegistration =
[TIP]
====
The top-level metadata methods are details about the relying party.
The methods inside `assertingPartyDetails` are details about the asserting party.
The methods inside `AssertingPartyMetadata` are details about the asserting party.
====

[NOTE]
Expand Down
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/servlet/saml2/logout.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ It's common to need to set other values in the `<saml2:LogoutRequest>` than the

By default, Spring Security will issue a `<saml2:LogoutRequest>` and supply:

* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceLocation`
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceLocation`
* The `ID` attribute - a GUID
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
* The `<NameID>` element - from `Authentication#getName`
Expand Down Expand Up @@ -424,7 +424,7 @@ It's common to need to set other values in the `<saml2:LogoutResponse>` than the

By default, Spring Security will issue a `<saml2:LogoutResponse>` and supply:

* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyDetails#getSingleLogoutServiceResponseLocation`
* The `Destination` attribute - from `RelyingPartyRegistration#getAssertingPartyMetadata#getSingleLogoutServiceResponseLocation`
* The `ID` attribute - a GUID
* The `<Issuer>` element - from `RelyingPartyRegistration#getEntityId`
* The `<Status>` element - `SUCCESS`
Expand Down
15 changes: 7 additions & 8 deletions docs/modules/ROOT/pages/servlet/saml2/metadata.adoc
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[[servlet-saml2login-metadata]]
= Saml 2.0 Metadata

Spring Security can <<parsing-asserting-party-metadata,parse asserting party metadata>> to produce an `AssertingPartyDetails` instance as well as <<publishing-relying-party-metadata,publish relying party metadata>> from a `RelyingPartyRegistration` instance.
Spring Security can <<parsing-asserting-party-metadata,parse asserting party metadata>> to produce an `AssertingPartyMetadata` instance as well as <<publishing-relying-party-metadata,publish relying party metadata>> from a `RelyingPartyRegistration` instance.

[[parsing-asserting-party-metadata]]
== Parsing `<saml2:IDPSSODescriptor>` metadata

You can parse an asserting party's metadata xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistrationrepository[using `RelyingPartyRegistrations`].

When using the OpenSAML vendor support, the resulting `AssertingPartyDetails` will be of type `OpenSamlAssertingPartyDetails`.
When using the OpenSAML vendor support, the resulting `AssertingPartyMetadata` will be of type `OpenSamlAssertingPartyDetails`.
This means you'll be able to do get the underlying OpenSAML XMLObject by doing the following:

[tabs]
Expand All @@ -18,7 +18,7 @@ Java::
[source,java,role="primary"]
----
OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails)
registration.getAssertingPartyDetails();
registration.getAssertingPartyMetadata();
EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor();
----
Expand All @@ -27,7 +27,7 @@ Kotlin::
[source,kotlin,role="secondary"]
----
val details: OpenSamlAssertingPartyDetails =
registration.getAssertingPartyDetails() as OpenSamlAssertingPartyDetails
registration.getAssertingPartyMetadata() as OpenSamlAssertingPartyDetails
val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor()
----
======
Expand Down Expand Up @@ -76,8 +76,7 @@ public class RefreshableRelyingPartyRegistrationRepository
}
private RelyingPartyRegistration applyRelyingParty(AssertingPartyMetadata metadata) {
AssertingPartyDetails details = (AssertingPartyDetails) metadata;
return RelyingPartyRegistration.withAssertingPartyDetails(details)
return RelyingPartyRegistration.withAssertingPartyMetadata(metadata)
// apply any relying party configuration
.build();
}
Expand Down Expand Up @@ -110,8 +109,8 @@ class RefreshableRelyingPartyRegistrationRepository : IterableRelyingPartyRegist
}
private fun applyRelyingParty(metadata: AssertingPartyMetadata): RelyingPartyRegistration {
val details: AssertingPartyDetails = metadata as AssertingPartyDetails
return RelyingPartyRegistration.withAssertingPartyDetails(details)
val details: AssertingPartyMetadata = metadata as AssertingPartyMetadata
return RelyingPartyRegistration.withAssertingPartyMetadata(details)
// apply any relying party configuration
.build()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ public static Converter<ResponseToken, Saml2ResponseValidatorResult> createDefau
result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_DESTINATION, message));
}
String assertingPartyEntityId = token.getRelyingPartyRegistration()
.getAssertingPartyDetails()
.getAssertingPartyMetadata()
.getEntityId();
if (!StringUtils.hasText(issuer) || !issuer.equals(assertingPartyEntityId)) {
String message = String.format("Invalid issuer [%s] for SAML response [%s]", issuer, response.getID());
Expand Down Expand Up @@ -775,7 +775,7 @@ private static ValidationContext createValidationContext(AssertionToken assertio
RelyingPartyRegistration relyingPartyRegistration = token.getRelyingPartyRegistration();
String audience = relyingPartyRegistration.getEntityId();
String recipient = relyingPartyRegistration.getAssertionConsumerServiceLocation();
String assertingPartyEntityId = relyingPartyRegistration.getAssertingPartyDetails().getEntityId();
String assertingPartyEntityId = relyingPartyRegistration.getAssertingPartyMetadata().getEntityId();
Map<String, Object> params = new HashMap<>();
Assertion assertion = assertionToken.getAssertion();
if (assertionContainsInResponseTo(assertion)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ static QueryParametersPartial sign(RelyingPartyRegistration registration) {
private static SignatureSigningParameters resolveSigningParameters(
RelyingPartyRegistration relyingPartyRegistration) {
List<Credential> credentials = resolveSigningCredentials(relyingPartyRegistration);
List<String> algorithms = relyingPartyRegistration.getAssertingPartyDetails().getSigningAlgorithms();
List<String> algorithms = relyingPartyRegistration.getAssertingPartyMetadata().getSigningAlgorithms();
List<String> digests = Collections.singletonList(SignatureConstants.ALGO_ID_DIGEST_SHA256);
String canonicalization = SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
SignatureSigningParametersResolver resolver = new SAMLMetadataSignatureSigningParametersResolver();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ static VerifierPartial verifySignature(RequestAbstractType object, RelyingPartyR

static SignatureTrustEngine trustEngine(RelyingPartyRegistration registration) {
Set<Credential> credentials = new HashSet<>();
Collection<Saml2X509Credential> keys = registration.getAssertingPartyDetails().getVerificationX509Credentials();
Collection<Saml2X509Credential> keys = registration.getAssertingPartyMetadata()
.getVerificationX509Credentials();
for (Saml2X509Credential key : keys) {
BasicX509Credential cred = new BasicX509Credential(key.getCertificate());
cred.setUsageType(UsageType.SIGNING);
cred.setEntityId(registration.getAssertingPartyDetails().getEntityId());
cred.setEntityId(registration.getAssertingPartyMetadata().getEntityId());
credentials.add(cred);
}
CredentialResolver credentialsResolver = new CollectionCredentialResolver(credentials);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public Saml2MessageBinding getBinding() {
* @since 5.7
*/
public static Builder withRelyingPartyRegistration(RelyingPartyRegistration registration) {
String location = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation();
String location = registration.getAssertingPartyMetadata().getSingleSignOnServiceLocation();
return new Builder(registration).authenticationRequestUri(location);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public Saml2MessageBinding getBinding() {
* @since 5.7
*/
public static Builder withRelyingPartyRegistration(RelyingPartyRegistration registration) {
String location = registration.getAssertingPartyDetails().getSingleSignOnServiceLocation();
String location = registration.getAssertingPartyMetadata().getSingleSignOnServiceLocation();
return new Builder(registration).authenticationRequestUri(location);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private Consumer<Collection<Saml2Error>> validateIssuer(LogoutRequest request,
return;
}
String issuer = request.getIssuer().getValue();
if (!issuer.equals(registration.getAssertingPartyDetails().getEntityId())) {
if (!issuer.equals(registration.getAssertingPartyMetadata().getEntityId())) {
errors
.add(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, "Failed to match issuer to configured issuer"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private Consumer<Collection<Saml2Error>> validateIssuer(LogoutResponse response,
return;
}
String issuer = response.getIssuer().getValue();
if (!issuer.equals(registration.getAssertingPartyDetails().getEntityId())) {
if (!issuer.equals(registration.getAssertingPartyMetadata().getEntityId())) {
errors
.add(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, "Failed to match issuer to configured issuer"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,12 @@ private CriteriaSet verificationCriteria(Issuer issuer) {

private SignatureTrustEngine trustEngine(RelyingPartyRegistration registration) {
Set<Credential> credentials = new HashSet<>();
Collection<Saml2X509Credential> keys = registration.getAssertingPartyDetails()
Collection<Saml2X509Credential> keys = registration.getAssertingPartyMetadata()
.getVerificationX509Credentials();
for (Saml2X509Credential key : keys) {
BasicX509Credential cred = new BasicX509Credential(key.getCertificate());
cred.setUsageType(UsageType.SIGNING);
cred.setEntityId(registration.getAssertingPartyDetails().getEntityId());
cred.setEntityId(registration.getAssertingPartyMetadata().getEntityId());
credentials.add(cred);
}
CredentialResolver credentialsResolver = new CollectionCredentialResolver(credentials);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ public static final class Builder {

private Builder(RelyingPartyRegistration registration) {
this.registration = registration;
this.location = registration.getAssertingPartyDetails().getSingleLogoutServiceLocation();
this.binding = registration.getAssertingPartyDetails().getSingleLogoutServiceBinding();
this.location = registration.getAssertingPartyMetadata().getSingleLogoutServiceLocation();
this.binding = registration.getAssertingPartyMetadata().getSingleLogoutServiceBinding();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ public static final class Builder {
private Function<Map<String, String>, String> encoder = DEFAULT_ENCODER;

private Builder(RelyingPartyRegistration registration) {
this.location = registration.getAssertingPartyDetails().getSingleLogoutServiceResponseLocation();
this.binding = registration.getAssertingPartyDetails().getSingleLogoutServiceBinding();
this.location = registration.getAssertingPartyMetadata().getSingleLogoutServiceResponseLocation();
this.binding = registration.getAssertingPartyMetadata().getSingleLogoutServiceBinding();
}

/**
Expand Down
Loading

0 comments on commit 6a5eb3b

Please sign in to comment.