mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-13 13:53:29 +00:00
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:
parent
4269cb0d26
commit
8e8a642e5a
@ -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,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
* <EntityDescriptor EntityID="..."/>
|
||||||
|
*
|
||||||
|
* <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 <AssertionConsumerService Location="..."/>
|
||||||
|
* in the relying party's <SPSSODescriptor>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* <EntityDescriptor EntityID="..."/>
|
||||||
|
*
|
||||||
|
* <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 <SingleSignOnService Location="..."/>
|
||||||
|
* in the asserting party's <IDPSSODescriptor>.
|
||||||
|
*
|
||||||
|
* @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 <SingleSignOnService Binding="..."/>
|
||||||
|
* in the asserting party's <IDPSSODescriptor>.
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* <EntityDescriptor EntityID="..."/>
|
||||||
|
*
|
||||||
|
* @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 <SingleSignOnService Location="..."/>
|
||||||
|
* in the asserting party's <IDPSSODescriptor>.
|
||||||
|
*
|
||||||
|
* @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 <SingleSignOnService Binding="..."/>
|
||||||
|
* in the asserting party's <IDPSSODescriptor>.
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* <EntityDescriptor EntityID="..."/>
|
||||||
*
|
*
|
||||||
* @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 >)}
|
* <EntityDescriptor EntityID="..."/>
|
||||||
*/
|
*
|
||||||
@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 <AssertionConsumerService Location="..."/>
|
||||||
|
* in the relying party's <SPSSODescriptor>
|
||||||
|
*
|
||||||
|
* <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
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
);
|
);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user