Use Spec Language in RelyingPartyRegistration

Changed conventions to better follow the metadata descriptors that
the registration is meant to represent.

Closes gh-8777
This commit is contained in:
Josh Cummings 2020-07-01 11:29:32 -06:00
parent 4269cb0d26
commit 8e8a642e5a
No known key found for this signature in database
GPG Key ID: 49EF60DD7FF83443
11 changed files with 470 additions and 192 deletions

View File

@ -57,7 +57,7 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
@Override @Override
public Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) { public Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
AuthnRequest authnRequest = createAuthnRequest(context); AuthnRequest authnRequest = createAuthnRequest(context);
String xml = context.getRelyingPartyRegistration().getProviderDetails().isSignAuthNRequest() ? String xml = context.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned() ?
this.saml.serialize(authnRequest, context.getRelyingPartyRegistration().getSigningCredentials()) : this.saml.serialize(authnRequest, context.getRelyingPartyRegistration().getSigningCredentials()) :
this.saml.serialize(authnRequest); this.saml.serialize(authnRequest);
@ -78,7 +78,7 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
result.samlRequest(deflatedAndEncoded) result.samlRequest(deflatedAndEncoded)
.relayState(context.getRelayState()); .relayState(context.getRelayState());
if (context.getRelyingPartyRegistration().getProviderDetails().isSignAuthNRequest()) { if (context.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
List<Saml2X509Credential> signingCredentials = context.getRelyingPartyRegistration().getSigningCredentials(); List<Saml2X509Credential> signingCredentials = context.getRelyingPartyRegistration().getSigningCredentials();
Map<String, String> signedParams = this.saml.signQueryParameters( Map<String, String> signedParams = this.saml.signQueryParameters(
signingCredentials, signingCredentials,

View File

@ -91,7 +91,7 @@ public class Saml2AuthenticationRequestContext {
* @return the Destination value * @return the Destination value
*/ */
public String getDestination() { public String getDestination() {
return this.getRelyingPartyRegistration().getProviderDetails().getWebSsoUrl(); return this.getRelyingPartyRegistration().getAssertingPartyDetails().getSingleSignOnServiceLocation();
} }
/** /**

View File

@ -16,125 +16,178 @@
package org.springframework.security.saml2.provider.service.registration; package org.springframework.security.saml2.provider.service.registration;
import org.springframework.security.saml2.credentials.Saml2X509Credential;
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType;
import org.springframework.util.Assert;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import static java.util.Collections.unmodifiableList; import org.springframework.security.saml2.credentials.Saml2X509Credential;
import static org.springframework.util.Assert.hasText; import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType;
import static org.springframework.util.Assert.notEmpty; import org.springframework.util.Assert;
import static org.springframework.util.Assert.notNull;
/** /**
* Represents a configured service provider, SP, and a remote identity provider, IDP, pair. * Represents a configured relying party (aka Service Provider) and asserting party (aka Identity Provider) pair.
* Each SP/IDP pair is uniquely identified using a <code>registrationId</code>, an arbitrary string. *
* A fully configured registration may look like * <p>
* Each RP/AP pair is uniquely identified using a {@code registrationId}, an arbitrary string.
*
* <p>
* A fully configured registration may look like:
*
* <pre> * <pre>
* //remote IDP entity ID * String registrationId = "simplesamlphp";
* String idpEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php"; *
* //remote WebSSO Endpoint - Where to Send AuthNRequests to * String relyingPartyEntityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
* String webSsoEndpoint = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php"; * String assertionConsumerServiceLocation = "{baseUrl}/login/saml2/sso/{registrationId}";
* //local registration ID * Saml2X509Credential relyingPartySigningCredential = ...;
* String registrationId = "simplesamlphp"; *
* //local entity ID - autogenerated based on URL * String assertingPartyEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
* String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}"; * String singleSignOnServiceLocation = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
* //local SSO URL - autogenerated, endpoint to receive SAML Response objects * Saml2X509Credential assertingPartyVerificationCredential = ...;
* String acsUrlTemplate = "{baseUrl}/login/saml2/sso/{registrationId}"; *
* //local signing (and local decryption key and remote encryption certificate) *
* Saml2X509Credential signingCredential = getSigningCredential(); * RelyingPartyRegistration rp = RelyingPartyRegistration.withRegistrationId(registrationId)
* //IDP certificate for verification of incoming messages * .entityId(relyingPartyEntityId)
* Saml2X509Credential idpVerificationCertificate = getVerificationCertificate(); * .assertionConsumerServiceLocation(assertingConsumerServiceLocation)
* RelyingPartyRegistration rp = RelyingPartyRegistration.withRegistrationId(registrationId) * .credentials(c -> c.add(relyingPartySigningCredential))
* .providerDetails(config -> config.entityId(idpEntityId)); * .assertingPartyDetails(details -> details
* .providerDetails(config -> config.webSsoUrl(url)); * .entityId(assertingPartyEntityId));
* .credentials(c -> c.add(signingCredential)) * .singleSignOnServiceLocation(singleSignOnServiceLocation))
* .credentials(c -> c.add(idpVerificationCertificate)) * .credentials(c -> c.add(assertingPartyVerificationCredential))
* .localEntityIdTemplate(localEntityIdTemplate) * .build();
* .assertionConsumerServiceUrlTemplate(acsUrlTemplate)
* .build();
* </pre> * </pre>
*
* @since 5.2 * @since 5.2
* @author Filip Hanik
* @author Josh Cummings
*/ */
public class RelyingPartyRegistration { public class RelyingPartyRegistration {
private final String registrationId; private final String registrationId;
private final String assertionConsumerServiceUrlTemplate; private final String entityId;
private final List<Saml2X509Credential> credentials; private final String assertionConsumerServiceLocation;
private final String localEntityIdTemplate;
private final ProviderDetails providerDetails; private final ProviderDetails providerDetails;
private final List<Saml2X509Credential> credentials;
private RelyingPartyRegistration( private RelyingPartyRegistration(
String registrationId, String registrationId,
String assertionConsumerServiceUrlTemplate, String entityId,
String assertionConsumerServiceLocation,
ProviderDetails providerDetails, ProviderDetails providerDetails,
List<Saml2X509Credential> credentials, List<Saml2X509Credential> credentials) {
String localEntityIdTemplate) {
hasText(registrationId, "registrationId cannot be empty"); Assert.hasText(registrationId, "registrationId cannot be empty");
hasText(assertionConsumerServiceUrlTemplate, "assertionConsumerServiceUrlTemplate cannot be empty"); Assert.hasText(entityId, "entityId cannot be empty");
hasText(localEntityIdTemplate, "localEntityIdTemplate cannot be empty"); Assert.hasText(assertionConsumerServiceLocation, "assertionConsumerServiceLocation cannot be empty");
notEmpty(credentials, "credentials cannot be empty"); Assert.notNull(providerDetails, "providerDetails cannot be null");
notNull(providerDetails, "providerDetails cannot be null"); Assert.notEmpty(credentials, "credentials cannot be empty");
hasText(providerDetails.webSsoUrl, "providerDetails.webSsoUrl cannot be empty");
for (Saml2X509Credential c : credentials) { for (Saml2X509Credential c : credentials) {
notNull(c, "credentials cannot contain null elements"); Assert.notNull(c, "credentials cannot contain null elements");
} }
this.registrationId = registrationId; this.registrationId = registrationId;
this.assertionConsumerServiceUrlTemplate = assertionConsumerServiceUrlTemplate; this.entityId = entityId;
this.credentials = unmodifiableList(new LinkedList<>(credentials)); this.assertionConsumerServiceLocation = assertionConsumerServiceLocation;
this.providerDetails = providerDetails; this.providerDetails = providerDetails;
this.localEntityIdTemplate = localEntityIdTemplate; this.credentials = Collections.unmodifiableList(new LinkedList<>(credentials));
}
/**
* Get the unique registration id for this RP/AP pair
*
* @return the unique registration id for this RP/AP pair
*/
public String getRegistrationId() {
return this.registrationId;
}
/**
* Get the relying party's
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
*
* <p>
* Equivalent to the value found in the relying party's
* &lt;EntityDescriptor EntityID="..."/&gt;
*
* <p>
* This value may contain a number of placeholders, which need to be
* resolved before use. They are {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
*
* @return the relying party's EntityID
* @since 5.4
*/
public String getEntityId() {
return this.entityId;
}
/**
* Get the AssertionConsumerService Location.
* Equivalent to the value found in &lt;AssertionConsumerService Location="..."/&gt;
* in the relying party's &lt;SPSSODescriptor&gt;.
*
* This value may contain a number of placeholders, which need to be
* resolved before use. They are {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
*
* @return the AssertionConsumerService Location
* @since 5.4
*/
public String getAssertionConsumerServiceLocation() {
return this.assertionConsumerServiceLocation;
}
/**
* Get the configuration details for the Asserting Party
*
* @return the {@link AssertingPartyDetails}
* @since 5.4
*/
public AssertingPartyDetails getAssertingPartyDetails() {
return this.providerDetails.assertingPartyDetails;
} }
/** /**
* Returns the entity ID of the IDP, the asserting party. * Returns the entity ID of the IDP, the asserting party.
* @return entity ID of the asserting party * @return entity ID of the asserting party
* @deprecated use {@link ProviderDetails#getEntityId()} from {@link #getProviderDetails()} * @deprecated use {@link AssertingPartyDetails#getEntityId} from {@link #getAssertingPartyDetails}
*/ */
@Deprecated @Deprecated
public String getRemoteIdpEntityId() { public String getRemoteIdpEntityId() {
return this.providerDetails.getEntityId(); return this.providerDetails.getEntityId();
} }
/**
* Returns the unique relying party registration ID
* @return registrationId
*/
public String getRegistrationId() {
return this.registrationId;
}
/** /**
* returns the URL template for which ACS URL authentication requests should contain * returns the URL template for which ACS URL authentication requests should contain
* Possible variables are {@code baseUrl}, {@code registrationId}, * Possible variables are {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}. * {@code baseScheme}, {@code baseHost}, and {@code basePort}.
* @return string containing the ACS URL template, with or without variables present * @return string containing the ACS URL template, with or without variables present
* @deprecated Use {@link #getAssertionConsumerServiceLocation} instead
*/ */
@Deprecated
public String getAssertionConsumerServiceUrlTemplate() { public String getAssertionConsumerServiceUrlTemplate() {
return this.assertionConsumerServiceUrlTemplate; return this.assertionConsumerServiceLocation;
} }
/** /**
* Contains the URL for which to send the SAML 2 Authentication Request to initiate * Contains the URL for which to send the SAML 2 Authentication Request to initiate
* a single sign on flow. * a single sign on flow.
* @return a IDP URL that accepts REDIRECT or POST binding for authentication requests * @return a IDP URL that accepts REDIRECT or POST binding for authentication requests
* @deprecated use {@link ProviderDetails#getWebSsoUrl()} from {@link #getProviderDetails()} * @deprecated use {@link AssertingPartyDetails#getSingleSignOnServiceLocation} from {@link #getAssertingPartyDetails}
*/ */
@Deprecated @Deprecated
public String getIdpWebSsoUrl() { public String getIdpWebSsoUrl() {
return this.getProviderDetails().webSsoUrl; return this.getAssertingPartyDetails().getSingleSignOnServiceLocation();
} }
/** /**
* Returns specific configuration around the Identity Provider SSO endpoint * Returns specific configuration around the Identity Provider SSO endpoint
* @return the IDP SSO endpoint configuration * @return the IDP SSO endpoint configuration
* @since 5.3 * @since 5.3
* @deprecated Use {@link #getAssertingPartyDetails} instead
*/ */
@Deprecated
public ProviderDetails getProviderDetails() { public ProviderDetails getProviderDetails() {
return this.providerDetails; return this.providerDetails;
} }
@ -145,9 +198,11 @@ public class RelyingPartyRegistration {
* {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example * {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}} * {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
* @return a string containing the entity ID or entity ID template * @return a string containing the entity ID or entity ID template
* @deprecated Use {@link #getEntityId} instead
*/ */
@Deprecated
public String getLocalEntityIdTemplate() { public String getLocalEntityIdTemplate() {
return this.localEntityIdTemplate; return this.entityId;
} }
/** /**
@ -223,40 +278,196 @@ public class RelyingPartyRegistration {
public static Builder withRelyingPartyRegistration(RelyingPartyRegistration registration) { public static Builder withRelyingPartyRegistration(RelyingPartyRegistration registration) {
Assert.notNull(registration, "registration cannot be null"); Assert.notNull(registration, "registration cannot be null");
return withRegistrationId(registration.getRegistrationId()) return withRegistrationId(registration.getRegistrationId())
.providerDetails(c -> { .entityId(registration.getEntityId())
c.webSsoUrl(registration.getProviderDetails().getWebSsoUrl()); .assertionConsumerServiceLocation(registration.getAssertionConsumerServiceLocation())
c.binding(registration.getProviderDetails().getBinding()); .assertingPartyDetails(c -> c
c.signAuthNRequest(registration.getProviderDetails().isSignAuthNRequest()); .entityId(registration.getAssertingPartyDetails().getEntityId())
c.entityId(registration.getProviderDetails().getEntityId()); .wantAuthnRequestsSigned(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned())
}) .singleSignOnServiceLocation(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.credentials(c -> c.addAll(registration.getCredentials())) .singleSignOnServiceBinding(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.localEntityIdTemplate(registration.getLocalEntityIdTemplate()) )
.assertionConsumerServiceUrlTemplate(registration.getAssertionConsumerServiceUrlTemplate()) .credentials(c -> c.addAll(registration.getCredentials()));
; }
/**
* The configuration metadata of the Asserting party
*
* @since 5.4
*/
public final static class AssertingPartyDetails {
private final String entityId;
private final boolean wantAuthnRequestsSigned;
private final String singleSignOnServiceLocation;
private final Saml2MessageBinding singleSignOnServiceBinding;
private AssertingPartyDetails(
String entityId,
boolean wantAuthnRequestsSigned,
String singleSignOnServiceLocation,
Saml2MessageBinding singleSignOnServiceBinding) {
Assert.hasText(entityId, "entityId cannot be null or empty");
Assert.notNull(singleSignOnServiceLocation, "singleSignOnServiceLocation cannot be null");
Assert.notNull(singleSignOnServiceBinding, "singleSignOnServiceBinding cannot be null");
this.entityId = entityId;
this.wantAuthnRequestsSigned = wantAuthnRequestsSigned;
this.singleSignOnServiceLocation = singleSignOnServiceLocation;
this.singleSignOnServiceBinding = singleSignOnServiceBinding;
}
/**
* Get the asserting party's
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
*
* <p>
* Equivalent to the value found in the asserting party's
* &lt;EntityDescriptor EntityID="..."/&gt;
*
* <p>
* This value may contain a number of placeholders, which need to be
* resolved before use. They are {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
*
* @return the asserting party's EntityID
*/
public String getEntityId() {
return this.entityId;
}
/**
* Get the WantAuthnRequestsSigned setting, indicating the asserting party's preference that
* relying parties should sign the AuthnRequest before sending.
*
* @return the WantAuthnRequestsSigned value
*/
public boolean getWantAuthnRequestsSigned() {
return this.wantAuthnRequestsSigned;
}
/**
* Get the
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
* Location.
*
* <p>
* Equivalent to the value found in &lt;SingleSignOnService Location="..."/&gt;
* in the asserting party's &lt;IDPSSODescriptor&gt;.
*
* @return the SingleSignOnService Location
*/
public String getSingleSignOnServiceLocation() {
return this.singleSignOnServiceLocation;
}
/**
* Get the
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
* Binding.
*
* <p>
* Equivalent to the value found in &lt;SingleSignOnService Binding="..."/&gt;
* in the asserting party's &lt;IDPSSODescriptor&gt;.
*
* @return the SingleSignOnService Location
*/
public Saml2MessageBinding getSingleSignOnServiceBinding() {
return this.singleSignOnServiceBinding;
}
public final static class Builder {
private String entityId;
private boolean wantAuthnRequestsSigned = true;
private String singleSignOnServiceLocation;
private Saml2MessageBinding singleSignOnServiceBinding = Saml2MessageBinding.REDIRECT;
/**
* Set the asserting party's
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
* Equivalent to the value found in the asserting party's
* &lt;EntityDescriptor EntityID="..."/&gt;
*
* @param entityId the asserting party's EntityID
* @return the {@link ProviderDetails.Builder} for further configuration
*/
public Builder entityId(String entityId) {
this.entityId = entityId;
return this;
}
/**
* Set the WantAuthnRequestsSigned setting, indicating the asserting party's preference that
* relying parties should sign the AuthnRequest before sending.
*
* @param wantAuthnRequestsSigned the WantAuthnRequestsSigned setting
* @return the {@link ProviderDetails.Builder} for further configuration
*/
public Builder wantAuthnRequestsSigned(boolean wantAuthnRequestsSigned) {
this.wantAuthnRequestsSigned = wantAuthnRequestsSigned;
return this;
}
/**
* Set the
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
* Location.
*
* <p>
* Equivalent to the value found in &lt;SingleSignOnService Location="..."/&gt;
* in the asserting party's &lt;IDPSSODescriptor&gt;.
*
* @param singleSignOnServiceLocation the SingleSignOnService Location
* @return the {@link ProviderDetails.Builder} for further configuration
*/
public Builder singleSignOnServiceLocation(String singleSignOnServiceLocation) {
this.singleSignOnServiceLocation = singleSignOnServiceLocation;
return this;
}
/**
* Set the
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
* Binding.
*
* <p>
* Equivalent to the value found in &lt;SingleSignOnService Binding="..."/&gt;
* in the asserting party's &lt;IDPSSODescriptor&gt;.
*
* @param singleSignOnServiceBinding the SingleSignOnService Binding
* @return the {@link ProviderDetails.Builder} for further configuration
*/
public Builder singleSignOnServiceBinding(Saml2MessageBinding singleSignOnServiceBinding) {
this.singleSignOnServiceBinding = singleSignOnServiceBinding;
return this;
}
/**
* Creates an immutable ProviderDetails object representing the configuration for an Identity Provider, IDP
* @return immutable ProviderDetails object
*/
public AssertingPartyDetails build() {
return new AssertingPartyDetails(
this.entityId,
this.wantAuthnRequestsSigned,
this.singleSignOnServiceLocation,
this.singleSignOnServiceBinding
);
}
}
} }
/** /**
* Configuration for IDP SSO endpoint configuration * Configuration for IDP SSO endpoint configuration
* @since 5.3 * @since 5.3
* @deprecated Use {@link AssertingPartyDetails} instead
*/ */
@Deprecated
public final static class ProviderDetails { public final static class ProviderDetails {
private final String entityId; private final AssertingPartyDetails assertingPartyDetails;
private final String webSsoUrl;
private final boolean signAuthNRequest;
private final Saml2MessageBinding binding;
private ProviderDetails( private ProviderDetails(AssertingPartyDetails assertingPartyDetails) {
String entityId, Assert.notNull("assertingPartyDetails cannot be null");
String webSsoUrl, this.assertingPartyDetails = assertingPartyDetails;
boolean signAuthNRequest,
Saml2MessageBinding binding) {
hasText(entityId, "entityId cannot be null or empty");
notNull(webSsoUrl, "webSsoUrl cannot be null");
notNull(binding, "binding cannot be null");
this.entityId = entityId;
this.webSsoUrl = webSsoUrl;
this.signAuthNRequest = signAuthNRequest;
this.binding = binding;
} }
/** /**
@ -264,7 +475,7 @@ public class RelyingPartyRegistration {
* @return the entity ID of the IDP * @return the entity ID of the IDP
*/ */
public String getEntityId() { public String getEntityId() {
return entityId; return this.assertingPartyDetails.getEntityId();
} }
/** /**
@ -273,7 +484,7 @@ public class RelyingPartyRegistration {
* @return a IDP URL that accepts REDIRECT or POST binding for authentication requests * @return a IDP URL that accepts REDIRECT or POST binding for authentication requests
*/ */
public String getWebSsoUrl() { public String getWebSsoUrl() {
return webSsoUrl; return this.assertingPartyDetails.getSingleSignOnServiceLocation();
} }
/** /**
@ -281,34 +492,38 @@ public class RelyingPartyRegistration {
* {@code false} if no signature is required. * {@code false} if no signature is required.
*/ */
public boolean isSignAuthNRequest() { public boolean isSignAuthNRequest() {
return signAuthNRequest; return this.assertingPartyDetails.getWantAuthnRequestsSigned();
} }
/** /**
* @return the type of SAML 2 Binding the AuthNRequest should be sent on * @return the type of SAML 2 Binding the AuthNRequest should be sent on
*/ */
public Saml2MessageBinding getBinding() { public Saml2MessageBinding getBinding() {
return binding; return this.assertingPartyDetails.getSingleSignOnServiceBinding();
} }
/** /**
* Builder for IDP SSO endpoint configuration * Builder for IDP SSO endpoint configuration
* @since 5.3 * @since 5.3
* @deprecated Use {@link AssertingPartyDetails.Builder} instead
*/ */
@Deprecated
public final static class Builder { public final static class Builder {
private String entityId; private final AssertingPartyDetails.Builder assertingPartyDetailsBuilder =
private String webSsoUrl; new AssertingPartyDetails.Builder();
private boolean signAuthNRequest = true;
private Saml2MessageBinding binding = Saml2MessageBinding.REDIRECT;
/** /**
* Sets the {@code EntityID} for the remote asserting party, the Identity Provider. * Set the asserting party's
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
* Equivalent to the value found in the asserting party's
* &lt;EntityDescriptor EntityID="..."/&gt;
* *
* @param entityId - the EntityID of the IDP. May be a URL. * @param entityId the asserting party's EntityID
* @return this object * @return the {@link Builder} for further configuration
* @since 5.4
*/ */
public Builder entityId(String entityId) { public Builder entityId(String entityId) {
this.entityId = entityId; this.assertingPartyDetailsBuilder.entityId(entityId);
return this; return this;
} }
@ -319,7 +534,7 @@ public class RelyingPartyRegistration {
* @return this object * @return this object
*/ */
public Builder webSsoUrl(String url) { public Builder webSsoUrl(String url) {
this.webSsoUrl = url; this.assertingPartyDetailsBuilder.singleSignOnServiceLocation(url);
return this; return this;
} }
@ -330,7 +545,7 @@ public class RelyingPartyRegistration {
* @return this object * @return this object
*/ */
public Builder signAuthNRequest(boolean signAuthNRequest) { public Builder signAuthNRequest(boolean signAuthNRequest) {
this.signAuthNRequest = signAuthNRequest; this.assertingPartyDetailsBuilder.wantAuthnRequestsSigned(signAuthNRequest);
return this; return this;
} }
@ -342,7 +557,7 @@ public class RelyingPartyRegistration {
* @return this object * @return this object
*/ */
public Builder binding(Saml2MessageBinding binding) { public Builder binding(Saml2MessageBinding binding) {
this.binding = binding; this.assertingPartyDetailsBuilder.singleSignOnServiceBinding(binding);
return this; return this;
} }
@ -351,22 +566,17 @@ public class RelyingPartyRegistration {
* @return immutable ProviderDetails object * @return immutable ProviderDetails object
*/ */
public ProviderDetails build() { public ProviderDetails build() {
return new ProviderDetails( return new ProviderDetails(this.assertingPartyDetailsBuilder.build());
this.entityId,
this.webSsoUrl,
this.signAuthNRequest,
this.binding
);
} }
} }
} }
public final static class Builder { public final static class Builder {
private String registrationId; private String registrationId;
private String assertionConsumerServiceUrlTemplate; private String entityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
private List<Saml2X509Credential> credentials = new LinkedList<>(); private String assertionConsumerServiceLocation;
private String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
private ProviderDetails.Builder providerDetails = new ProviderDetails.Builder(); private ProviderDetails.Builder providerDetails = new ProviderDetails.Builder();
private List<Saml2X509Credential> credentials = new LinkedList<>();
private Builder(String registrationId) { private Builder(String registrationId) {
this.registrationId = registrationId; this.registrationId = registrationId;
@ -384,49 +594,54 @@ public class RelyingPartyRegistration {
} }
/** /**
* Sets the {@code entityId} for the remote asserting party, the Identity Provider. * Set the relying party's
* @param entityId the IDP entityId * <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
* @return this object * Equivalent to the value found in the relying party's
* @deprecated use {@link #providerDetails(Consumer< ProviderDetails.Builder >)} * &lt;EntityDescriptor EntityID="..."/&gt;
*/ *
@Deprecated * This value may contain a number of placeholders.
public Builder remoteIdpEntityId(String entityId) { * They are {@code baseUrl}, {@code registrationId},
this.providerDetails(idp -> idp.entityId(entityId));
return this;
}
/**
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">Assertion Consumer
* Service</a> URL template. It can contain variables {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}. * {@code baseScheme}, {@code baseHost}, and {@code basePort}.
* @param assertionConsumerServiceUrlTemplate the Assertion Consumer Service URL template (i.e. *
* "{baseUrl}/login/saml2/sso/{registrationId}". * @return the {@link Builder} for further configuration
* @return this object * @since 5.4
*/ */
public Builder assertionConsumerServiceUrlTemplate(String assertionConsumerServiceUrlTemplate) { public Builder entityId(String entityId) {
this.assertionConsumerServiceUrlTemplate = assertionConsumerServiceUrlTemplate; this.entityId = entityId;
return this; return this;
} }
/** /**
* Sets the {@code SSO URL} for the remote asserting party, the Identity Provider. * Set the <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">AssertionConsumerService</a>
* @param url - a URL that accepts authentication requests via REDIRECT or POST bindings * Location.
* @return this object *
* @deprecated use {@link #providerDetails(Consumer< ProviderDetails.Builder >)} * <p>
* Equivalent to the value found in &lt;AssertionConsumerService Location="..."/&gt;
* in the relying party's &lt;SPSSODescriptor&gt;
*
* <p>
* This value may contain a number of placeholders.
* They are {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
*
* @param assertionConsumerServiceLocation
* @return the {@link Builder} for further configuration
* @since 5.4
*/ */
@Deprecated public Builder assertionConsumerServiceLocation(String assertionConsumerServiceLocation) {
public Builder idpWebSsoUrl(String url) { this.assertionConsumerServiceLocation = assertionConsumerServiceLocation;
providerDetails(config -> config.webSsoUrl(url));
return this; return this;
} }
/** /**
* Configures the IDP SSO endpoint * Apply this {@link Consumer} to further configure the Asserting Party details
* @param providerDetails a consumer that configures the IDP SSO endpoint *
* @return this object * @param assertingPartyDetails The {@link Consumer} to apply
* @return the {@link Builder} for further configuration
* @since 5.4
*/ */
public Builder providerDetails(Consumer<ProviderDetails.Builder> providerDetails) { public Builder assertingPartyDetails(Consumer<AssertingPartyDetails.Builder> assertingPartyDetails) {
providerDetails.accept(this.providerDetails); assertingPartyDetails.accept(this.providerDetails.assertingPartyDetailsBuilder);
return this; return this;
} }
@ -449,16 +664,68 @@ public class RelyingPartyRegistration {
return this; return this;
} }
/**
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">Assertion Consumer
* Service</a> URL template. It can contain variables {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
* @param assertionConsumerServiceUrlTemplate the Assertion Consumer Service URL template (i.e.
* "{baseUrl}/login/saml2/sso/{registrationId}".
* @return this object
* @deprecated Use {@link #assertionConsumerServiceLocation} instead.
*/
@Deprecated
public Builder assertionConsumerServiceUrlTemplate(String assertionConsumerServiceUrlTemplate) {
this.assertionConsumerServiceLocation = assertionConsumerServiceUrlTemplate;
return this;
}
/**
* Sets the {@code entityId} for the remote asserting party, the Identity Provider.
* @param entityId the IDP entityId
* @return this object
* @deprecated use {@link #assertingPartyDetails(Consumer< AssertingPartyDetails.Builder >)}
*/
@Deprecated
public Builder remoteIdpEntityId(String entityId) {
assertingPartyDetails(idp -> idp.entityId(entityId));
return this;
}
/**
* Sets the {@code SSO URL} for the remote asserting party, the Identity Provider.
* @param url - a URL that accepts authentication requests via REDIRECT or POST bindings
* @return this object
* @deprecated use {@link #assertingPartyDetails(Consumer< AssertingPartyDetails.Builder >)}
*/
@Deprecated
public Builder idpWebSsoUrl(String url) {
assertingPartyDetails(config -> config.singleSignOnServiceLocation(url));
return this;
}
/** /**
* Sets the local relying party, or Service Provider, entity Id template. * Sets the local relying party, or Service Provider, entity Id template.
* can generate it's entity ID based on possible variables of {@code baseUrl}, {@code registrationId}, * can generate it's entity ID based on possible variables of {@code baseUrl}, {@code registrationId},
* {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example * {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}} * {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
* @return a string containing the entity ID or entity ID template * @return a string containing the entity ID or entity ID template
* @deprecated Use {@link #entityId} instead
*/ */
@Deprecated
public Builder localEntityIdTemplate(String template) { public Builder localEntityIdTemplate(String template) {
this.localEntityIdTemplate = template; this.entityId = template;
return this;
}
/**
* Configures the IDP SSO endpoint
* @param providerDetails a consumer that configures the IDP SSO endpoint
* @return this object
* @deprecated Use {@link #assertingPartyDetails} instead
*/
@Deprecated
public Builder providerDetails(Consumer<ProviderDetails.Builder> providerDetails) {
providerDetails.accept(this.providerDetails);
return this; return this;
} }
@ -469,10 +736,10 @@ public class RelyingPartyRegistration {
public RelyingPartyRegistration build() { public RelyingPartyRegistration build() {
return new RelyingPartyRegistration( return new RelyingPartyRegistration(
this.registrationId, this.registrationId,
this.assertionConsumerServiceUrlTemplate, this.entityId,
this.assertionConsumerServiceLocation,
this.providerDetails.build(), this.providerDetails.build(),
this.credentials, this.credentials
this.localEntityIdTemplate
); );
} }
} }

View File

@ -40,7 +40,7 @@ final class Saml2ServletUtils {
return baseUrl; return baseUrl;
} }
String entityId = relyingParty.getProviderDetails().getEntityId(); String entityId = relyingParty.getAssertingPartyDetails().getEntityId();
String registrationId = relyingParty.getRegistrationId(); String registrationId = relyingParty.getRegistrationId();
Map<String, String> uriVariables = new HashMap<>(); Map<String, String> uriVariables = new HashMap<>();
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl) UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl)

View File

@ -98,11 +98,11 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce
throw new Saml2AuthenticationException(saml2Error); throw new Saml2AuthenticationException(saml2Error);
} }
String applicationUri = Saml2ServletUtils.getApplicationUri(request); String applicationUri = Saml2ServletUtils.getApplicationUri(request);
String localSpEntityId = Saml2ServletUtils.resolveUrlTemplate(rp.getLocalEntityIdTemplate(), applicationUri, rp); String localSpEntityId = Saml2ServletUtils.resolveUrlTemplate(rp.getEntityId(), applicationUri, rp);
final Saml2AuthenticationToken authentication = new Saml2AuthenticationToken( final Saml2AuthenticationToken authentication = new Saml2AuthenticationToken(
responseXml, responseXml,
request.getRequestURL().toString(), request.getRequestURL().toString(),
rp.getProviderDetails().getEntityId(), rp.getAssertingPartyDetails().getEntityId(),
localSpEntityId, localSpEntityId,
rp.getCredentials() rp.getCredentials()
); );

View File

@ -16,6 +16,12 @@
package org.springframework.security.saml2.provider.service.servlet.filter; package org.springframework.security.saml2.provider.service.servlet.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
@ -36,12 +42,6 @@ import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.ISO_8859_1;
/** /**
@ -155,7 +155,7 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
return; return;
} }
Saml2AuthenticationRequestContext context = authenticationRequestContextResolver.resolve(request, relyingParty); Saml2AuthenticationRequestContext context = authenticationRequestContextResolver.resolve(request, relyingParty);
if (relyingParty.getProviderDetails().getBinding() == Saml2MessageBinding.REDIRECT) { if (relyingParty.getAssertingPartyDetails().getSingleSignOnServiceBinding() == Saml2MessageBinding.REDIRECT) {
sendRedirect(response, context); sendRedirect(response, context);
} else { } else {
sendPost(response, context); sendPost(response, context);

View File

@ -67,8 +67,8 @@ public final class DefaultSaml2AuthenticationRequestContextResolver implements S
String applicationUri = getApplicationUri(request); String applicationUri = getApplicationUri(request);
Function<String, String> resolver = templateResolver(applicationUri, relyingParty); Function<String, String> resolver = templateResolver(applicationUri, relyingParty);
String localSpEntityId = resolver.apply(relyingParty.getLocalEntityIdTemplate()); String localSpEntityId = resolver.apply(relyingParty.getEntityId());
String assertionConsumerServiceUrl = resolver.apply(relyingParty.getAssertionConsumerServiceUrlTemplate()); String assertionConsumerServiceUrl = resolver.apply(relyingParty.getAssertionConsumerServiceLocation());
return Saml2AuthenticationRequestContext.builder() return Saml2AuthenticationRequestContext.builder()
.issuer(localSpEntityId) .issuer(localSpEntityId)
.relyingPartyRegistration(relyingParty) .relyingPartyRegistration(relyingParty)
@ -82,7 +82,7 @@ public final class DefaultSaml2AuthenticationRequestContextResolver implements S
} }
private static String resolveUrlTemplate(String template, String baseUrl, RelyingPartyRegistration relyingParty) { private static String resolveUrlTemplate(String template, String baseUrl, RelyingPartyRegistration relyingParty) {
String entityId = relyingParty.getProviderDetails().getEntityId(); String entityId = relyingParty.getAssertingPartyDetails().getEntityId();
String registrationId = relyingParty.getRegistrationId(); String registrationId = relyingParty.getRegistrationId();
Map<String, String> uriVariables = new HashMap<>(); Map<String, String> uriVariables = new HashMap<>();
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl) UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl)

View File

@ -52,7 +52,7 @@ public class OpenSamlAuthenticationRequestFactoryTests {
@Before @Before
public void setUp() { public void setUp() {
relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("id") relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("id")
.assertionConsumerServiceUrlTemplate("template") .assertionConsumerServiceLocation("template")
.providerDetails(c -> c.webSsoUrl("https://destination/sso")) .providerDetails(c -> c.webSsoUrl("https://destination/sso"))
.providerDetails(c -> c.entityId("remote-entity-id")) .providerDetails(c -> c.entityId("remote-entity-id"))
.localEntityIdTemplate("local-entity-id") .localEntityIdTemplate("local-entity-id")

View File

@ -42,9 +42,13 @@ public class RelyingPartyRegistrationTests {
.isEqualTo("simplesamlphp"); .isEqualTo("simplesamlphp");
assertThat(copy.getProviderDetails().getEntityId()) assertThat(copy.getProviderDetails().getEntityId())
.isEqualTo(registration.getProviderDetails().getEntityId()) .isEqualTo(registration.getProviderDetails().getEntityId())
.isEqualTo(copy.getAssertingPartyDetails().getEntityId())
.isEqualTo(registration.getAssertingPartyDetails().getEntityId())
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php"); .isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php");
assertThat(copy.getAssertionConsumerServiceUrlTemplate()) assertThat(copy.getAssertionConsumerServiceUrlTemplate())
.isEqualTo(registration.getAssertionConsumerServiceUrlTemplate()) .isEqualTo(registration.getAssertionConsumerServiceUrlTemplate())
.isEqualTo(copy.getAssertionConsumerServiceLocation())
.isEqualTo(registration.getAssertionConsumerServiceLocation())
.isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI); .isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
assertThat(copy.getCredentials()) assertThat(copy.getCredentials())
.containsAll(registration.getCredentials()) .containsAll(registration.getCredentials())
@ -54,15 +58,23 @@ public class RelyingPartyRegistrationTests {
); );
assertThat(copy.getLocalEntityIdTemplate()) assertThat(copy.getLocalEntityIdTemplate())
.isEqualTo(registration.getLocalEntityIdTemplate()) .isEqualTo(registration.getLocalEntityIdTemplate())
.isEqualTo(copy.getEntityId())
.isEqualTo(registration.getEntityId())
.isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}"); .isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
assertThat(copy.getProviderDetails().getWebSsoUrl()) assertThat(copy.getProviderDetails().getWebSsoUrl())
.isEqualTo(registration.getProviderDetails().getWebSsoUrl()) .isEqualTo(registration.getProviderDetails().getWebSsoUrl())
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php"); .isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php");
assertThat(copy.getProviderDetails().getBinding()) assertThat(copy.getProviderDetails().getBinding())
.isEqualTo(registration.getProviderDetails().getBinding()) .isEqualTo(registration.getProviderDetails().getBinding())
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(POST); .isEqualTo(POST);
assertThat(copy.getProviderDetails().isSignAuthNRequest()) assertThat(copy.getProviderDetails().isSignAuthNRequest())
.isEqualTo(registration.getProviderDetails().isSignAuthNRequest()) .isEqualTo(registration.getProviderDetails().isSignAuthNRequest())
.isEqualTo(copy.getAssertingPartyDetails().getWantAuthnRequestsSigned())
.isEqualTo(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned())
.isFalse(); .isFalse();
} }
} }

View File

@ -28,26 +28,24 @@ import static org.springframework.security.saml2.credentials.TestSaml2X509Creden
public class TestRelyingPartyRegistrations { public class TestRelyingPartyRegistrations {
public static RelyingPartyRegistration.Builder relyingPartyRegistration() { public static RelyingPartyRegistration.Builder relyingPartyRegistration() {
//remote IDP entity ID
String idpEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
//remote WebSSO Endpoint - Where to Send AuthNRequests to
String webSsoEndpoint = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
//local registration ID
String registrationId = "simplesamlphp"; String registrationId = "simplesamlphp";
//local entity ID - autogenerated based on URL
String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}"; String rpEntityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
//local signing (and decryption key)
Saml2X509Credential signingCredential = relyingPartySigningCredential(); Saml2X509Credential signingCredential = relyingPartySigningCredential();
//IDP certificate for verification of incoming messages String assertionConsumerServiceLocation = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
Saml2X509Credential idpVerificationCertificate = relyingPartyVerifyingCredential();
String acsUrlTemplate = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI; String apEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
Saml2X509Credential verificationCertificate = relyingPartyVerifyingCredential();
String singleSignOnServiceLocation = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
return RelyingPartyRegistration.withRegistrationId(registrationId) return RelyingPartyRegistration.withRegistrationId(registrationId)
.providerDetails(c -> c.entityId(idpEntityId)) .entityId(rpEntityId)
.providerDetails(c -> c.webSsoUrl(webSsoEndpoint)) .assertionConsumerServiceLocation(assertionConsumerServiceLocation)
.credentials(c -> c.add(signingCredential)) .credentials(c -> c.add(signingCredential))
.credentials(c -> c.add(idpVerificationCertificate)) .providerDetails(c -> c
.localEntityIdTemplate(localEntityIdTemplate) .entityId(apEntityId)
.assertionConsumerServiceUrlTemplate(acsUrlTemplate); .webSsoUrl(singleSignOnServiceLocation))
.credentials(c -> c.add(verificationCertificate));
} }

View File

@ -15,6 +15,12 @@
*/ */
package org.springframework.security.samples.config; package org.springframework.security.samples.config;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@ -25,12 +31,6 @@ import org.springframework.security.saml2.provider.service.registration.InMemory
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION; import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION;
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING; import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING;
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION; import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION;
@ -54,12 +54,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
Saml2X509Credential idpVerificationCertificate = getVerificationCertificate(); Saml2X509Credential idpVerificationCertificate = getVerificationCertificate();
String acsUrlTemplate = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI; String acsUrlTemplate = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
return RelyingPartyRegistration.withRegistrationId(registrationId) return RelyingPartyRegistration.withRegistrationId(registrationId)
.providerDetails(config -> config.entityId(idpEntityId)) .entityId(localEntityIdTemplate)
.providerDetails(config -> config.webSsoUrl(webSsoEndpoint)) .assertionConsumerServiceLocation(acsUrlTemplate)
.credentials(c -> c.add(signingCredential)) .credentials(c -> c.add(signingCredential))
.credentials(c -> c.add(idpVerificationCertificate)) .assertingPartyDetails(config -> config
.localEntityIdTemplate(localEntityIdTemplate) .entityId(idpEntityId)
.assertionConsumerServiceUrlTemplate(acsUrlTemplate) .singleSignOnServiceLocation(webSsoEndpoint))
.credentials(c -> c.add(idpVerificationCertificate))
.build(); .build();
} }