package edu.internet2.middleware.shibboleth.idp.profile.saml1;
-import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
+import org.opensaml.common.SAMLObject;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLVersion;
-import org.opensaml.common.binding.BindingException;
-import org.opensaml.common.binding.encoding.MessageEncoder;
import org.opensaml.common.impl.SAMLObjectContentReference;
+import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml1.core.Assertion;
+import org.opensaml.saml1.core.Audience;
+import org.opensaml.saml1.core.AudienceRestrictionCondition;
+import org.opensaml.saml1.core.Conditions;
+import org.opensaml.saml1.core.ConfirmationMethod;
+import org.opensaml.saml1.core.NameIdentifier;
+import org.opensaml.saml1.core.RequestAbstractType;
import org.opensaml.saml1.core.Response;
+import org.opensaml.saml1.core.ResponseAbstractType;
+import org.opensaml.saml1.core.Statement;
import org.opensaml.saml1.core.Status;
import org.opensaml.saml1.core.StatusCode;
import org.opensaml.saml1.core.StatusMessage;
-import org.opensaml.saml2.metadata.Endpoint;
+import org.opensaml.saml1.core.Subject;
+import org.opensaml.saml1.core.SubjectConfirmation;
+import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
+import org.opensaml.saml2.metadata.AuthnAuthorityDescriptor;
+import org.opensaml.saml2.metadata.NameIDFormat;
+import org.opensaml.saml2.metadata.PDPDescriptor;
import org.opensaml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.SSODescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.xml.XMLObjectBuilder;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.Signer;
+import org.opensaml.xml.util.DatatypeHelper;
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
+import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
+import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncoder;
+import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncodingException;
import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
-
/**
* Common implementation details for profile handlers.
*/
public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
-
+
/** SAML Version for this profile handler. */
public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
-
+
/** Class logger. */
private static Logger log = Logger.getLogger(AbstractSAML1ProfileHandler.class);
-
+
+ /** Builder of Response objects. */
+ private SAMLObjectBuilder<Response> responseBuilder;
+
+ /** Builder of Assertion objects. */
+ private SAMLObjectBuilder<Assertion> assertionBuilder;
+
+ /** Builder of Conditions objects. */
+ private SAMLObjectBuilder<Conditions> conditionsBuilder;
+
+ /** Builder of AudienceRestrictionCondition objects. */
+ private SAMLObjectBuilder<AudienceRestrictionCondition> audienceRestrictionConditionBuilder;
+
+ /** Builder of AudienceRestrictionCondition objects. */
+ private SAMLObjectBuilder<Audience> audienceBuilder;
+
+ /** Builder of NameIdentifier objects. */
+ private SAMLObjectBuilder<NameIdentifier> nameIdBuilder;
+
+ /** Builder of SubjectConfirmation objects. */
+ private SAMLObjectBuilder<SubjectConfirmation> subjectConfirmationBuilder;
+
+ /** Builder of ConfirmationMethod objects. */
+ private SAMLObjectBuilder<ConfirmationMethod> confirmationMethodBuilder;
+
+ /** Builder of Subject objects. */
+ private SAMLObjectBuilder<Subject> subjectBuilder;
+
/** Builder for Status objects. */
- protected SAMLObjectBuilder<Status> statusBuilder;
-
+ private SAMLObjectBuilder<Status> statusBuilder;
+
/** Builder for StatusCode objects. */
- protected SAMLObjectBuilder<StatusCode> statusCodeBuilder;
-
+ private SAMLObjectBuilder<StatusCode> statusCodeBuilder;
+
/** Builder for StatusMessage objects. */
- protected SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
-
+ private SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
+
/** For building signature. */
private XMLObjectBuilder<Signature> signatureBuilder;
-
+
/**
* Default constructor.
*/
@SuppressWarnings("unchecked")
- public AbstractSAML1ProfileHandler(){
+ public AbstractSAML1ProfileHandler() {
super();
- statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
- statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
- statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
- signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
- }
-
- /**
- * Build a SAML 1 Status element.
- *
- * @param statusCode The status code - see oasis-sstc-saml-core-1.1, section 3.4.3.1.
- * @param statusMessage The status message, or <code>null</code> if none is to be set.
- *
- * @return The Status object, or <code>null</code> on error.
- */
- protected Status buildStatus(String statusCode, String statusMessage) {
-
- if (statusCode == null || statusCode.equals("")) {
- return null;
- }
-
- Status status = statusBuilder.buildObject();
- StatusCode sc = statusCodeBuilder.buildObject();
- sc.setValue(statusCode);
- status.setStatusCode(sc);
-
- if (statusMessage != null || !(statusMessage.equals(""))) {
-
- StatusMessage sm = statusMessageBuilder.buildObject();
- sm.setMessage(statusMessage);
- status.setStatusMessage(sm);
- }
-
+ responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
+ assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
+ .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
+ conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
+ Conditions.DEFAULT_ELEMENT_NAME);
+ audienceRestrictionConditionBuilder = (SAMLObjectBuilder<AudienceRestrictionCondition>) getBuilderFactory()
+ .getBuilder(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
+ audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
+ nameIdBuilder = (SAMLObjectBuilder<NameIdentifier>) getBuilderFactory().getBuilder(
+ NameIdentifier.DEFAULT_ELEMENT_NAME);
+ subjectConfirmationBuilder = (SAMLObjectBuilder<SubjectConfirmation>) getBuilderFactory().getBuilder(
+ SubjectConfirmation.DEFAULT_ELEMENT_NAME);
+ confirmationMethodBuilder = (SAMLObjectBuilder<ConfirmationMethod>) getBuilderFactory().getBuilder(
+ ConfirmationMethod.DEFAULT_ELEMENT_NAME);
+ subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
+ statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
+ statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
+ StatusCode.DEFAULT_ELEMENT_NAME);
+ statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(
+ StatusMessage.DEFAULT_ELEMENT_NAME);
+ signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Response builder.
+ *
+ * @return SAML 1 Response builder
+ */
+ public SAMLObjectBuilder<Response> getResponseBuilder() {
+ return responseBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Assertion builder.
+ *
+ * @return SAML 1 Assertion builder
+ */
+ public SAMLObjectBuilder<Assertion> getAssertionBuilder() {
+ return assertionBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Conditions builder.
+ *
+ * @return SAML 1 Conditions builder
+ */
+ public SAMLObjectBuilder<Conditions> getConditionsBuilder() {
+ return conditionsBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 AudienceRestrictionCondition builder.
+ *
+ * @return SAML 1 AudienceRestrictionCondition builder
+ */
+ public SAMLObjectBuilder<AudienceRestrictionCondition> getAudienceRestrictionConditionBuilder() {
+ return audienceRestrictionConditionBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Audience builder.
+ *
+ * @return SAML 1 Audience builder
+ */
+ public SAMLObjectBuilder<Audience> getAudienceBuilder() {
+ return audienceBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 NameIdentifier builder.
+ *
+ * @return SAML 1 NameIdentifier builder
+ */
+ public SAMLObjectBuilder<NameIdentifier> getNameIdentifierBuilder() {
+ return nameIdBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 SubjectConfirmation builder.
+ *
+ * @return SAML 1 SubjectConfirmation builder
+ */
+ public SAMLObjectBuilder<SubjectConfirmation> getSubjectConfirmationBuilder() {
+ return subjectConfirmationBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 ConfirmationMethod builder.
+ *
+ * @return SAML 1 ConfirmationMethod builder
+ */
+ public SAMLObjectBuilder<ConfirmationMethod> getConfirmationMethodBuilder() {
+ return confirmationMethodBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Subject builder.
+ *
+ * @return SAML 1 Subject builder
+ */
+ public SAMLObjectBuilder<Subject> getSubjectBuilder() {
+ return subjectBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 Status builder.
+ *
+ * @return SAML 1 Status builder
+ */
+ public SAMLObjectBuilder<Status> getStatusBuilder() {
+ return statusBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 StatusCode builder.
+ *
+ * @return SAML 2 StatusCode builder
+ */
+ public SAMLObjectBuilder<StatusCode> getStatusCodeBuilder() {
+ return statusCodeBuilder;
+ }
+
+ /**
+ * Convenience method for getting the SAML 1 StatusMessage builder.
+ *
+ * @return SAML StatusMessage builder
+ */
+ public SAMLObjectBuilder<StatusMessage> getStatusMessageBuilder() {
+ return statusMessageBuilder;
+ }
+
+ /**
+ * Builds a response to the attribute query within the request context.
+ *
+ * @param requestContext current request context
+ * @param statements the statements to include in the response
+ *
+ * @return the built response
+ *
+ * @throws ProfileException thrown if there is a problem creating the SAML response
+ * @throws AttributeRequestException thrown if there is a problem resolving attributes
+ */
+ protected Response buildResponse(SAML1ProfileRequestContext requestContext, List<Statement> statements)
+ throws ProfileException, AttributeRequestException {
+
+ DateTime issueInstant = new DateTime();
+
+ // create the assertion and add the attribute statement
+ Assertion assertion = buildAssertion(requestContext, issueInstant);
+ if (statements != null) {
+ assertion.getStatements().addAll(statements);
+ }
+
+ // create the SAML response and add the assertion
+ Response samlResponse = getResponseBuilder().buildObject();
+ samlResponse.setIssueInstant(issueInstant);
+ populateStatusResponse(requestContext, samlResponse);
+
+ samlResponse.getAssertions().add(assertion);
+
+ // sign the assertion if it should be signed
+ signAssertion(requestContext, assertion);
+
+ Status status = buildStatus(StatusCode.SUCCESS, null, null);
+ samlResponse.setStatus(status);
+
+ return samlResponse;
+ }
+
+ /**
+ * Builds a basic assertion with its id, issue instant, SAML version, issuer, subject, and conditions populated.
+ *
+ * @param requestContext current request context
+ * @param issueInstant time to use as assertion issue instant
+ *
+ * @return the built assertion
+ */
+ protected Assertion buildAssertion(SAML1ProfileRequestContext requestContext, DateTime issueInstant) {
+ Assertion assertion = getAssertionBuilder().buildObject();
+ assertion.setID(getIdGenerator().generateIdentifier());
+ assertion.setIssueInstant(issueInstant);
+ assertion.setVersion(SAMLVersion.VERSION_11);
+ assertion.setIssuer(requestContext.getAssertingPartyId());
+
+ Conditions conditions = buildConditions(requestContext, issueInstant);
+ assertion.setConditions(conditions);
+
+ return assertion;
+ }
+
+ /**
+ * Builds a SAML assertion condition set. The following fields are set; not before, not on or after, audience
+ * restrictions, and proxy restrictions.
+ *
+ * @param requestContext current request context
+ * @param issueInstant timestamp the assertion was created
+ *
+ * @return constructed conditions
+ */
+ protected Conditions buildConditions(SAML1ProfileRequestContext requestContext, DateTime issueInstant) {
+ AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
+ Conditions conditions = getConditionsBuilder().buildObject();
+ conditions.setNotBefore(issueInstant);
+ conditions.setNotOnOrAfter(issueInstant.plus(profileConfig.getAssertionLifetime()));
+
+ Collection<String> audiences;
+
+ // add audience restrictions
+ audiences = profileConfig.getAssertionAudiences();
+ if (audiences != null && audiences.size() > 0) {
+ AudienceRestrictionCondition audienceRestriction = getAudienceRestrictionConditionBuilder().buildObject();
+ for (String audienceUri : audiences) {
+ Audience audience = getAudienceBuilder().buildObject();
+ audience.setUri(audienceUri);
+ audienceRestriction.getAudiences().add(audience);
+ }
+ conditions.getAudienceRestrictionConditions().add(audienceRestriction);
+ }
+
+ return conditions;
+ }
+
+ /**
+ * Builds the SAML subject for the user for the service provider.
+ *
+ * @param requestContext current request context
+ * @param confirmationMethod subject confirmation method used for the subject
+ *
+ * @return SAML subject for the user for the service provider
+ *
+ * @throws ProfileException thrown if a NameID can not be created either because there was a problem encoding the
+ * name ID attribute or because there are no supported name formats
+ */
+ protected Subject buildSubject(SAML1ProfileRequestContext requestContext, String confirmationMethod)
+ throws ProfileException {
+ NameIdentifier nameID = buildNameId(requestContext);
+ requestContext.setSubjectNameID(nameID);
+
+ ConfirmationMethod method = getConfirmationMethodBuilder().buildObject();
+ method.setConfirmationMethod(confirmationMethod);
+
+ SubjectConfirmation subjectConfirmation = getSubjectConfirmationBuilder().buildObject();
+ subjectConfirmation.getConfirmationMethods().add(method);
+
+ Subject subject = getSubjectBuilder().buildObject();
+ subject.setNameIdentifier(nameID);
+ subject.setSubjectConfirmation(subjectConfirmation);
+
+ return subject;
+ }
+
+ /**
+ * Builds a NameIdentifier appropriate for this request. NameIdentifier are built by inspecting the SAML request and
+ * metadata, picking a name format that was requested by the relying party or is mutually supported by both the
+ * relying party and asserting party as described in their metadata entries. Once a set of supported name formats is
+ * determined the principals attributes are inspected for an attribtue supported an attribute encoder whose category
+ * is one of the supported name formats.
+ *
+ * @param requestContext current request context
+ *
+ * @return the NameIdentifier appropriate for this request
+ *
+ * @throws ProfileException thrown if a NameIdentifier can not be created either because there was a problem
+ * encoding the name ID attribute or because there are no supported name formats
+ */
+ protected NameIdentifier buildNameId(SAML1ProfileRequestContext requestContext) throws ProfileException {
+ if (log.isDebugEnabled()) {
+ log.debug("Building assertion NameIdentifier to relying party " + requestContext.getRelyingPartyId()
+ + " for principal " + requestContext.getPrincipalName());
+ }
+ Map<String, BaseAttribute> principalAttributes = requestContext.getPrincipalAttributes();
+ List<String> supportedNameFormats = getNameFormats(requestContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Supported name formats: " + supportedNameFormats);
+ }
+
+ if (principalAttributes != null && supportedNameFormats != null) {
+ try {
+ AttributeEncoder<NameIdentifier> nameIdEncoder = null;
+ for (BaseAttribute attribute : principalAttributes.values()) {
+ for (String nameFormat : supportedNameFormats) {
+ nameIdEncoder = attribute.getEncoderByCategory(nameFormat);
+ if (nameIdEncoder != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Using attribute " + attribute.getId() + " suppoting name format "
+ + nameFormat + " to create the NameIdentifier for principal "
+ + requestContext.getPrincipalName());
+ }
+ return nameIdEncoder.encode(attribute);
+ }
+ }
+ }
+ } catch (AttributeEncodingException e) {
+ throw new ProfileException("Unable to encode NameIdentifier attribute", e);
+ }
+ }
+
+ throw new ProfileException("No principal attributes support NameIdentifier construction");
+ }
+
+ /**
+ * Gets the NameIdentifier format to use when creating NameIdentifiers for the relying party.
+ *
+ * @param requestContext current request context
+ *
+ * @return list of formats that may be used with the relying party
+ *
+ * @throws ProfileException thrown if there is a problem determing the NameIdentifier format to use
+ */
+ protected List<String> getNameFormats(SAML1ProfileRequestContext requestContext) throws ProfileException {
+ ArrayList<String> nameFormats = new ArrayList<String>();
+
+ try {
+ RoleDescriptor assertingPartyRole = getMetadataProvider().getRole(requestContext.getAssertingPartyId(),
+ requestContext.getAssertingPartyRole(), SAMLConstants.SAML1P_NS);
+ List<String> assertingPartySupportedFormats = getEntitySupportedFormats(assertingPartyRole);
+
+ if (nameFormats.isEmpty()) {
+ RoleDescriptor relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
+ requestContext.getRelyingPartyRole(), SAMLConstants.SAML1P_NS);
+ List<String> relyingPartySupportedFormats = getEntitySupportedFormats(relyingPartyRole);
+
+ assertingPartySupportedFormats.retainAll(relyingPartySupportedFormats);
+ nameFormats.addAll(assertingPartySupportedFormats);
+ }
+ if (nameFormats.isEmpty()) {
+ nameFormats.add("urn:oasis:names:tc:SAML:1.0:nameid-format:unspecified");
+ }
+
+ return nameFormats;
+
+ } catch (MetadataProviderException e) {
+ throw new ProfileException("Unable to determine lookup entity metadata", e);
+ }
+ }
+
+ /**
+ * Gets the list of NameIdentifier formats supported for a given role.
+ *
+ * @param role the role to get the list of supported NameIdentifier formats
+ *
+ * @return list of supported NameIdentifier formats
+ */
+ protected List<String> getEntitySupportedFormats(RoleDescriptor role) {
+ List<NameIDFormat> nameIDFormats = null;
+
+ if (role instanceof SSODescriptor) {
+ nameIDFormats = ((SSODescriptor) role).getNameIDFormats();
+ } else if (role instanceof AuthnAuthorityDescriptor) {
+ nameIDFormats = ((AuthnAuthorityDescriptor) role).getNameIDFormats();
+ } else if (role instanceof PDPDescriptor) {
+ nameIDFormats = ((PDPDescriptor) role).getNameIDFormats();
+ } else if (role instanceof AttributeAuthorityDescriptor) {
+ nameIDFormats = ((AttributeAuthorityDescriptor) role).getNameIDFormats();
+ }
+
+ ArrayList<String> supportedFormats = new ArrayList<String>();
+ if (nameIDFormats != null) {
+ for (NameIDFormat format : nameIDFormats) {
+ supportedFormats.add(format.getFormat());
+ }
+ }
+
+ return supportedFormats;
+ }
+
+ /**
+ * Constructs an SAML response message carrying a request error.
+ *
+ * @param requestContext current request context
+ * @param topLevelCode top-level status code
+ * @param secondLevelCode second-level status code
+ * @param failureMessage An optional second-level failure message
+ *
+ * @return the constructed error response
+ */
+ protected Response buildErrorResponse(SAML1ProfileRequestContext requestContext, String topLevelCode,
+ String secondLevelCode, String failureMessage) {
+ Response samlResponse = getResponseBuilder().buildObject();
+ samlResponse.setIssueInstant(new DateTime());
+ populateStatusResponse(requestContext, samlResponse);
+
+ Status status = buildStatus(topLevelCode, secondLevelCode, failureMessage);
+ samlResponse.setStatus(status);
+
+ return samlResponse;
+ }
+
+ /**
+ * Populates the response's id, in response to, issue instant, version, and issuer properties.
+ *
+ * @param requestContext current request context
+ * @param response the response to populate
+ */
+ protected void populateStatusResponse(SAML1ProfileRequestContext requestContext, ResponseAbstractType response) {
+ response.setID(getIdGenerator().generateIdentifier());
+
+ SAMLObject samlMessage = requestContext.getSamlRequest();
+ if (samlMessage != null && samlMessage instanceof RequestAbstractType) {
+ response.setInResponseTo(((RequestAbstractType) samlMessage).getID());
+ }
+ response.setVersion(SAMLVersion.VERSION_11);
+ }
+
+ /**
+ * Build a status message, with an optional second-level failure message.
+ *
+ * @param topLevelCode top-level status code
+ * @param secondLevelCode second-level status code
+ * @param failureMessage An optional second-level failure message
+ *
+ * @return a Status object.
+ */
+ protected Status buildStatus(String topLevelCode, String secondLevelCode, String failureMessage) {
+ Status status = getStatusBuilder().buildObject();
+
+ StatusCode statusCode = getStatusCodeBuilder().buildObject();
+ statusCode.setValue(DatatypeHelper.safeTrimOrNullString(topLevelCode));
+ status.setStatusCode(statusCode);
+
+ if (secondLevelCode != null) {
+ StatusCode secondLevelStatusCode = getStatusCodeBuilder().buildObject();
+ secondLevelStatusCode.setValue(DatatypeHelper.safeTrimOrNullString(secondLevelCode));
+ statusCode.setStatusCode(secondLevelStatusCode);
+ }
+
+ if (failureMessage != null) {
+ StatusMessage msg = getStatusMessageBuilder().buildObject();
+ msg.setMessage(failureMessage);
+ status.setStatusMessage(msg);
+ }
+
return status;
}
-
+
/**
* Signs the given assertion if either the current profile configuration or the relying party configuration contains
* signing credentials.
- *
+ *
+ * @param requestContext current request context
* @param assertion assertion to sign
- * @param rpConfig relying party configuration
- * @param profileConfig current profile configuration
+ *
+ * @throws ProfileException thrown if the metadata can not be located for the relying party or, if signing is
+ * required, if a signing credential is not configured
*/
- protected void signAssertion(Assertion assertion, RelyingPartyConfiguration rpConfig,
- AbstractSAML1ProfileConfiguration profileConfig) {
- if (!profileConfig.getSignAssertions()) {
+ protected void signAssertion(SAML1ProfileRequestContext requestContext, Assertion assertion)
+ throws ProfileException {
+ if (log.isDebugEnabled()) {
+ log.debug("Determining if SAML assertion to relying party " + requestContext.getRelyingPartyId()
+ + " should be signed");
+ }
+
+ boolean signAssertion = false;
+
+ RoleDescriptor relyingPartyRole;
+ try {
+ relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
+ requestContext.getRelyingPartyRole(), SAMLConstants.SAML20P_NS);
+ } catch (MetadataProviderException e) {
+ throw new ProfileException("Unable to lookup entity metadata for relying party "
+ + requestContext.getRelyingPartyId());
+ }
+ AbstractSAML1ProfileConfiguration profileConfig = requestContext.getProfileConfiguration();
+
+ if (relyingPartyRole instanceof SPSSODescriptor) {
+ SPSSODescriptor ssoDescriptor = (SPSSODescriptor) relyingPartyRole;
+ if (ssoDescriptor.getWantAssertionsSigned() != null) {
+ signAssertion = ssoDescriptor.getWantAssertionsSigned().booleanValue();
+ if (log.isDebugEnabled()) {
+ log.debug("Entity metadata for relying party " + requestContext.getRelyingPartyId()
+ + " indicates to sign assertions: " + signAssertion);
+ }
+ }
+ } else if (profileConfig.getSignAssertions()) {
+ signAssertion = true;
+ log.debug("IdP relying party configuration "
+ + requestContext.getRelyingPartyConfiguration().getRelyingPartyId()
+ + " indicates to sign assertions: " + signAssertion);
+ }
+
+ if (!signAssertion) {
return;
}
-
+
+ if (log.isDebugEnabled()) {
+ log.debug("Determining signing credntial for assertion to relying party "
+ + requestContext.getRelyingPartyId());
+ }
Credential signatureCredential = profileConfig.getSigningCredential();
if (signatureCredential == null) {
- signatureCredential = rpConfig.getDefaultSigningCredential();
+ signatureCredential = requestContext.getRelyingPartyConfiguration().getDefaultSigningCredential();
}
-
+
if (signatureCredential == null) {
- return;
+ throw new ProfileException("No signing credential is specified for relying party configuration "
+ + requestContext.getRelyingPartyConfiguration().getProviderId()
+ + " or it's SAML2 attribute query profile configuration");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Signing assertion to relying party " + requestContext.getRelyingPartyId());
}
-
SAMLObjectContentReference contentRef = new SAMLObjectContentReference(assertion);
Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
signature.getContentReferences().add(contentRef);
assertion.setSignature(signature);
-
+
Signer.signObject(signature);
}
-
- /**
- * Encode a SAML Response.
- *
- * @param binding The SAML protocol binding to use.
- * @param profileResponse The Raw output stream to send the message to.
- * @param samlResponse The SAML Response to send.
- * @param relyingParty The relying party to send the message to.
- * @param roleDescriptor The role of the message sender.
- * @param endpoint The endpoint to which the message should be send.
- *
- * @throws ProfileException On error.
- */
- protected void encodeResponse(String binding,final ProfileResponse<ServletResponse> profileResponse,
- final Response samlResponse, final RelyingPartyConfiguration relyingParty,
- final RoleDescriptor roleDescriptor, final Endpoint endpoint) throws ProfileException {
-
- MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(binding);
- if (encoder == null) {
- log.error("No MessageEncoder registered for " + binding);
- throw new ProfileException("No MessageEncoder registered for " + binding);
- }
-
- encoder.setResponse(profileResponse.getRawResponse());
- encoder.setIssuer(relyingParty.getProviderId());
- encoder.setMetadataProvider(getRelyingPartyConfigurationManager().getMetadataProvider());
- encoder.setRelyingPartyRole(roleDescriptor);
- encoder.setSigningCredential(relyingParty.getDefaultSigningCredential());
- encoder.setSamlMessage(samlResponse);
- encoder.setRelyingPartyEndpoint(endpoint);
-
- try {
- encoder.encode();
- } catch (BindingException ex) {
- log.error("Unable to encode response the relying party: " + relyingParty.getRelyingPartyId(), ex);
- throw new ProfileException("Unable to encode response the relying party: "
- + relyingParty.getRelyingPartyId(), ex);
+
+ /**
+ * Contextual object used to accumlate information as profile requests are being processed.
+ *
+ * @param <RequestType> type of SAML 1 request
+ * @param <ResponseType> type of SAML 1 response
+ * @param <ProfileConfigurationType> configuration type for this profile
+ */
+ protected class SAML1ProfileRequestContext<RequestType extends SAMLObject, ResponseType extends ResponseAbstractType, ProfileConfigurationType extends AbstractSAML1ProfileConfiguration>
+ extends SAMLProfileRequestContext {
+
+ /** SAML request message. */
+ private RequestType samlRequest;
+
+ /** SAML response message. */
+ private ResponseType samlResponse;
+
+ /** Request profile configuration. */
+ private ProfileConfigurationType profileConfiguration;
+
+ /** The NameIdentifier of the subject of this request. */
+ private NameIdentifier subjectNameIdentifier;
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public SAML1ProfileRequestContext(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+
+ /**
+ * Gets the NameIdentifier of the subject of this request.
+ *
+ * @return NameIdentifier of the subject of this request
+ */
+ public NameIdentifier getSubjectNameID() {
+ return subjectNameIdentifier;
+ }
+
+ /**
+ * Sets the NameIdentifier of the subject of this request.
+ *
+ * @param id NameIdentifier of the subject of this request
+ */
+ public void setSubjectNameID(NameIdentifier id) {
+ subjectNameIdentifier = id;
+ }
+
+ /**
+ * Gets the profile configuration for this request.
+ *
+ * @return profile configuration for this request
+ */
+ public ProfileConfigurationType getProfileConfiguration() {
+ return profileConfiguration;
+ }
+
+ /**
+ * Sets the profile configuration for this request.
+ *
+ * @param configuration profile configuration for this request
+ */
+ public void setProfileConfiguration(ProfileConfigurationType configuration) {
+ profileConfiguration = configuration;
+ }
+
+ /**
+ * Gets the SAML request message.
+ *
+ * @return SAML request message
+ */
+ public RequestType getSamlRequest() {
+ return samlRequest;
+ }
+
+ /**
+ * Sets the SAML request message.
+ *
+ * @param request SAML request message
+ */
+ public void setSamlRequest(RequestType request) {
+ samlRequest = request;
+ }
+
+ /**
+ * Gets the SAML response message.
+ *
+ * @return SAML response message
+ */
+ public ResponseType getSamlResponse() {
+ return samlResponse;
+ }
+
+ /**
+ * Sets the SAML response message.
+ *
+ * @param response SAML response message
+ */
+ public void setSamlResponse(ResponseType response) {
+ samlResponse = response;
}
-
}
}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package edu.internet2.middleware.shibboleth.idp.profile.saml1;
-
-import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.opensaml.common.SAMLObjectBuilder;
-import org.opensaml.common.binding.BindingException;
-import org.opensaml.saml1.core.Advice;
-import org.opensaml.saml1.core.Assertion;
-import org.opensaml.saml1.core.AttributeStatement;
-import org.opensaml.saml1.core.Conditions;
-import org.opensaml.saml1.core.Response;
-import org.opensaml.saml1.core.Status;
-import org.opensaml.saml1.core.StatusCode;
-import org.opensaml.saml1.core.Subject;
-import org.opensaml.saml1.core.SubjectStatement;
-import org.opensaml.xml.encryption.EncryptionException;
-
-import edu.internet2.middleware.shibboleth.common.attribute.filtering.AttributeFilteringException;
-import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
-
-/**
- * SAML 1 Attribute Query profile handler.
- */
-public class AttributeQuery extends AbstractSAML1ProfileHandler {
-
- /** {@inheritDoc} */
- public String getProfileId() {
- // TODO Auto-generated method stub
- return null;
- }
-
- /** {@inheritDoc} */
- public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) throws ProfileException {
- // TODO Auto-generated method stub
-
- }
-//
-// /** Class logger. */
-// private static Logger log = Logger.getLogger(AttributeQuery.class);
-//
-// /** {@inheritDoc} */
-// public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
-// if (log.isDebugEnabled()) {
-// log.debug("begin processRequest");
-// }
-//
-// // get message from the decoder
-// org.opensaml.saml1.core.AttributeQuery message = null;
-// try {
-// message = (org.opensaml.saml1.core.AttributeQuery) decodeMessage(request);
-// } catch (BindingException e) {
-// log.error("Error decoding attribute query message", e);
-// throw new ServletException("Error decoding attribute query message");
-// }
-//
-// // get attribute statement from attribute authority
-// AttributeAuthority aa = new AttributeAuthority();
-// aa.setAttributeResolver(getAttributeResolver());
-// aa.setFilteringEngine(getFilteringEngine());
-// aa.setRelyingPartyConfiguration(getRelyingPartyConfiguration());
-// aa.setSecurityPolicy(getDecoder().getSecurityPolicy());
-// aa.setRequest(request);
-// AttributeStatement statement = null;
-// try {
-// statement = aa.performAttributeQuery(message);
-// } catch (AttributeResolutionException e) {
-// log.error("Error resolving attributes", e);
-// throw new ServletException("Error resolving attributes");
-// } catch (FilteringException e) {
-// log.error("Error filtering attributes", e);
-// throw new ServletException("Error filtering attributes");
-// }
-//
-// // construct response
-// Response samlResponse = null;
-// try {
-// samlResponse = buildResponse(message, request.getRemoteHost(), new DateTime(), statement);
-// } catch (EncryptionException e) {
-// log.error("Error encrypting SAML response", e);
-// throw new ServletException("Error encrypting SAML response");
-// }
-// if (log.isDebugEnabled()) {
-// log.debug("built saml1 response: " + samlResponse);
-// }
-//
-// // encode response
-// try {
-// encodeResponse(samlResponse);
-// } catch (BindingException e) {
-// log.error("Error encoding attribute query response", e);
-// throw new ServletException("Error encoding attribute query response");
-// }
-//
-// return true;
-// }
-//
-// /**
-// * This builds the response for this SAML request.
-// *
-// * @param message <code>AttributeQuery</code>
-// * @param dest <code>String</code>
-// * @param issueInstant <code>DateTime</code>
-// * @param statement <code>AttributeStatement</code>
-// * @return <code>Response</code>
-// * @throws EncryptionException if an error occurs attempting to encrypt data
-// */
-// private Response buildResponse(org.opensaml.saml1.core.AttributeQuery message, String dest, DateTime issueInstant,
-// AttributeStatement statement) throws EncryptionException {
-// SAMLObjectBuilder<Response> responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(
-// Response.DEFAULT_ELEMENT_NAME);
-// /*
-// * required: samlp:Status, ID, Version, IssueInstant
-// */
-// Response response = responseBuilder.buildObject();
-// response.setVersion(SAML_VERSION);
-// response.setID(getIdGenerator().generateIdentifier());
-// response.setInResponseTo(getDecoder().getSecurityPolicy().getIssuer().toString());
-// response.setIssueInstant(issueInstant);
-// response.setRecipient(dest);
-//
-// response.setStatus(buildStatus());
-// response.getAssertions().add(buildAssertion(message.getSubject(), issueInstant, statement));
-// return response;
-// }
-//
-// /**
-// * This builds the status response for this SAML request.
-// *
-// * @return <code>Status</code>
-// */
-// private Status buildStatus() {
-// // build status
-// SAMLObjectBuilder<Status> statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(
-// Status.DEFAULT_ELEMENT_NAME);
-// Status status = statusBuilder.buildObject();
-//
-// // build status code
-// SAMLObjectBuilder<StatusCode> statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory()
-// .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
-// StatusCode statusCode = statusCodeBuilder.buildObject();
-// statusCode.setValue("Success");
-// status.setStatusCode(statusCode);
-// return status;
-// }
-//
-// /**
-// * This builds the assertion for this SAML request.
-// *
-// * @param messageSubject <code>Subject</code>
-// * @param issueInstant <code>DateTime</code>
-// * @param statement <code>AttributeStatement</code> of attributes
-// * @return <code>Assertion</code>
-// * @throws EncryptionException if an error occurs attempting to encrypt data
-// */
-// private Assertion buildAssertion(Subject messageSubject, DateTime issueInstant, AttributeStatement statement)
-// throws EncryptionException {
-// // build assertion
-// SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
-// Assertion.DEFAULT_ELEMENT_NAME);
-// /*
-// * required: saml:Issuer, ID, Version, IssueInstant
-// */
-// Assertion assertion = assertionBuilder.buildObject();
-// assertion.setID(getIdGenerator().generateIdentifier());
-// assertion.setIssueInstant(issueInstant);
-// assertion.setVersion(SAML_VERSION);
-// assertion.setIssuer(getRelyingPartyConfiguration().getProviderID());
-//
-// // build subject
-// assertion.getSubjectStatements().add(buildSubjectStatement(messageSubject));
-// // build conditions
-// assertion.setConditions(buildConditions(issueInstant));
-// // build advice
-// assertion.setAdvice(buildAdvice());
-// // add attribute statement
-// assertion.getAttributeStatements().add(statement);
-// return assertion;
-// }
-//
-// /**
-// * This builds the subject statement for this SAML request.
-// *
-// * @param messageSubject <code>Subject</code>
-// * @return <code>SubjectStatement</code>
-// */
-// private SubjectStatement buildSubjectStatement(Subject messageSubject) {
-// // build subject
-// SAMLObjectBuilder<SubjectStatement> subjectStatementBuilder = (SAMLObjectBuilder<SubjectStatement>) getBuilderFactory()
-// .getBuilder(SubjectStatement.DEFAULT_ELEMENT_NAME);
-// SubjectStatement subjectStatement = subjectStatementBuilder.buildObject();
-// subjectStatement.setSubject(messageSubject);
-// return subjectStatement;
-// }
-//
-// /**
-// * This builds the conditions for this SAML request.
-// *
-// * @param issueInstant <code>DateTime</code>
-// * @return <code>Conditions</code>
-// */
-// private Conditions buildConditions(DateTime issueInstant) {
-// SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
-// .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
-// Conditions conditions = conditionsBuilder.buildObject();
-// conditions.setNotBefore(issueInstant);
-// // TODO conditions.setNotOnOrAfter();
-// // TODO add additional conditions : conditions.getConditions().add(Condition);
-// // TODO what about AudienceRestriction, OneTimeUse, ProxyRestriction?
-// return conditions;
-// }
-//
-// /**
-// * This builds the advice for this SAML request.
-// *
-// * @return <code>Advice</code>
-// */
-// private Advice buildAdvice() {
-// SAMLObjectBuilder<Advice> adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(
-// Advice.DEFAULT_ELEMENT_NAME);
-// Advice advice = adviceBuilder.buildObject();
-// // advice.getAssertionIDReferences().add();
-// // advice.getAssertionURIReferences().add();
-// // advice.getAssertions().add();
-// // advice.getEncryptedAssertions().add();
-// // advice.addNamespace(namespace);
-// return advice;
-// }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.profile.saml1;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.log4j.Logger;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.common.binding.decoding.MessageDecoder;
+import org.opensaml.common.binding.encoding.MessageEncoder;
+import org.opensaml.common.binding.security.SAMLSecurityPolicy;
+import org.opensaml.saml1.binding.decoding.HTTPSOAP11Decoder;
+import org.opensaml.saml1.binding.encoding.HTTPSOAP11Encoder;
+import org.opensaml.saml1.core.AttributeQuery;
+import org.opensaml.saml1.core.AttributeStatement;
+import org.opensaml.saml1.core.NameIdentifier;
+import org.opensaml.saml1.core.Response;
+import org.opensaml.saml1.core.Statement;
+import org.opensaml.saml1.core.StatusCode;
+import org.opensaml.saml1.core.Subject;
+import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.ws.security.SecurityPolicyException;
+
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
+import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAMLAttributeRequestContext;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AttributeQueryConfiguration;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
+
+/**
+ * SAML 1 Attribute Query profile handler.
+ */
+public class AttributeQueryProfileHandler extends AbstractSAML1ProfileHandler {
+
+ /** Class logger. */
+ private final Logger log = Logger.getLogger(AttributeQueryProfileHandler.class);
+
+ /** {@inheritDoc} */
+ public String getProfileId() {
+ return "urn:mace:shibboleth:2.0:idp:profiles:saml1:query:attribute";
+ }
+
+ /** {@inheritDoc} */
+ public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
+ throws ProfileException {
+
+ AttributeQueryContext requestContext = new AttributeQueryContext(request, response);
+
+ Response samlResponse;
+ try {
+ decodeRequest(requestContext);
+
+ ArrayList<Statement> statements = new ArrayList<Statement>();
+ statements.add(buildAttributeStatement(requestContext));
+
+ samlResponse = buildResponse(requestContext, statements);
+ } catch (SecurityPolicyException e) {
+ samlResponse = buildErrorResponse(requestContext, StatusCode.REQUESTER, StatusCode.REQUEST_DENIED, e
+ .getMessage());
+ } catch (AttributeRequestException e) {
+ samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER, null, e.getMessage());
+ } catch (ProfileException e) {
+ samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER, StatusCode.REQUEST_DENIED, e
+ .getMessage());
+ }
+ }
+
+ /**
+ * Decodes the message in the request and adds it to the request context.
+ *
+ * @param requestContext request context contianing the request to decode
+ *
+ * @throws ProfileException throw if there is a problem decoding the request
+ * @throws SecurityPolicyException thrown if the message was decoded properly but did not meet the necessary
+ * security policy requirements
+ */
+ protected void decodeRequest(AttributeQueryContext requestContext) throws ProfileException, SecurityPolicyException {
+ if (log.isDebugEnabled()) {
+ log.debug("Decoding incomming request");
+ }
+ MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(
+ HTTPSOAP11Decoder.BINDING_URI);
+ if (decoder == null) {
+ throw new ProfileException("No request decoder was registered for binding type: "
+ + HTTPSOAP11Decoder.BINDING_URI);
+ }
+ super.populateMessageDecoder(decoder);
+
+ decoder.setRequest(requestContext.getProfileRequest().getRawRequest());
+ requestContext.setMessageDecoder(decoder);
+
+ try {
+ decoder.decode();
+ if (log.isDebugEnabled()) {
+ log.debug("Decoded request");
+ }
+ } catch (BindingException e) {
+ log.error("Error decoding attribute query message", e);
+ throw new ProfileException("Error decoding attribute query message");
+ } finally {
+ // Set as much information as can be retrieved from the decoded message
+ SAMLSecurityPolicy securityPolicy = requestContext.getMessageDecoder().getSecurityPolicy();
+ requestContext.setRelyingPartyId(securityPolicy.getIssuer());
+
+ RelyingPartyConfiguration rpConfig = getRelyingPartyConfiguration(requestContext.getRelyingPartyId());
+ requestContext.setRelyingPartyConfiguration(rpConfig);
+
+ requestContext.setRelyingPartyRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ requestContext.setAssertingPartyId(requestContext.getRelyingPartyConfiguration().getProviderId());
+
+ requestContext.setAssertingPartyRole(AttributeAuthorityDescriptor.DEFAULT_ELEMENT_NAME);
+
+ requestContext.setProfileConfiguration((AttributeQueryConfiguration) rpConfig
+ .getProfileConfiguration(AttributeQueryConfiguration.PROFILE_ID));
+
+ requestContext.setSamlRequest((AttributeQuery) requestContext.getMessageDecoder().getSAMLMessage());
+ }
+ }
+
+ /**
+ * Executes a query for attributes and builds a SAML attribute statement from the results.
+ *
+ * @param requestContext current request context
+ *
+ * @return attribute statement resulting from the query
+ *
+ * @throws ProfileException thrown if there is a problem making the query
+ * @throws AttributeRequestException thrown if there is a problem resolving attributes
+ */
+ protected AttributeStatement buildAttributeStatement(AttributeQueryContext requestContext) throws ProfileException,
+ AttributeRequestException {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Creating attribute statement in response to SAML request from relying party "
+ + requestContext.getRelyingPartyId());
+ }
+
+ try {
+ AttributeQueryConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+ if (profileConfiguration == null) {
+ log.error("No SAML 1 attribute query profile configuration is defined for relying party: "
+ + requestContext.getRelyingPartyId());
+ throw new AttributeRequestException("SAML 1 attribute query is not configured for this relying party");
+ }
+
+ SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
+
+ ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> attributeRequestContext = buildAttributeRequestContext(requestContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Resolving principal name for subject of SAML request from relying party "
+ + requestContext.getRelyingPartyId());
+ }
+ String principal = attributeAuthority.getPrincipal(attributeRequestContext);
+ requestContext.setPrincipalName(principal);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Resolving attributes for principal " + principal + " of SAML request from relying party "
+ + requestContext.getRelyingPartyId());
+ }
+ Map<String, BaseAttribute> principalAttributes = attributeAuthority
+ .getAttributes(buildAttributeRequestContext(requestContext));
+
+ requestContext.setPrincipalAttributes(principalAttributes);
+
+ AttributeStatement statment = attributeAuthority.buildAttributeStatement(requestContext.getSamlRequest(),
+ principalAttributes.values());
+
+ Subject statementSubject = buildSubject(requestContext, "urn:oasis:names:tc:SAML:1.0:cm:sender-vouches");
+ statment.setSubject(statementSubject);
+
+ return statment;
+ } catch (AttributeRequestException e) {
+ log.error("Error resolving attributes for SAML request from relying party "
+ + requestContext.getRelyingPartyId(), e);
+ throw e;
+ }
+ }
+
+ /**
+ * Creates an attribute query context from the current profile request context.
+ *
+ * @param requestContext current profile request
+ *
+ * @return created query context
+ */
+ protected ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> buildAttributeRequestContext(
+ AttributeQueryContext requestContext) {
+
+ ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> queryContext = new ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery>(
+ getMetadataProvider(), requestContext.getRelyingPartyConfiguration(), requestContext.getSamlRequest());
+
+ queryContext.setAttributeRequester(requestContext.getAssertingPartyId());
+ queryContext.setPrincipalName(requestContext.getPrincipalName());
+ queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
+ queryContext.setRequest(requestContext.getProfileRequest());
+
+ Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
+ if (userSession != null) {
+ queryContext.setUserSession(userSession);
+ ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
+ if (serviceInfo != null) {
+ String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
+
+ requestContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+ queryContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+ }
+ }
+
+ return queryContext;
+ }
+
+ /**
+ * Encodes the request's SAML response and writes it to the servlet response.
+ *
+ * @param requestContext current request context
+ *
+ * @throws ProfileException thrown if no message encoder is registered for this profiles binding
+ */
+ protected void encodeResponse(AttributeQueryContext requestContext) throws ProfileException {
+ if (log.isDebugEnabled()) {
+ log.debug("Encoding response to SAML request from relying party " + requestContext.getRelyingPartyId());
+ }
+ MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(
+ HTTPSOAP11Encoder.BINDING_URI);
+ if (encoder == null) {
+ throw new ProfileException("No response encoder was registered for binding type: "
+ + HTTPSOAP11Encoder.BINDING_URI);
+ }
+
+ super.populateMessageEncoder(encoder);
+ encoder.setResponse(requestContext.getProfileResponse().getRawResponse());
+ encoder.setSamlMessage(requestContext.getSamlResponse());
+ requestContext.setMessageEncoder(encoder);
+
+ try {
+ encoder.encode();
+ } catch (BindingException e) {
+ throw new ProfileException("Unable to encode response to relying party: "
+ + requestContext.getRelyingPartyId(), e);
+ }
+ }
+
+ /** Basic data structure used to accumulate information as a request is being processed. */
+ protected class AttributeQueryContext extends
+ SAML1ProfileRequestContext<AttributeQuery, Response, AttributeQueryConfiguration> {
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public AttributeQueryContext(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+ }
+}
\ No newline at end of file
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.opensaml.Configuration;
* Abstract SAML 2.0 Authentication Request profile handler.
*/
public abstract class AbstractAuthenticationRequest extends AbstractSAML2ProfileHandler {
-
-
+
/**
* Represents the internal state of a SAML 2.0 Authentiation Request while it's being processed by the IdP.
*/
protected class AuthenticationRequestContext {
-
+
/** The ProfileRequest. */
protected ProfileRequest<ServletRequest> profileRequest;
-
+
/** The ProfileResponse. */
protected ProfileResponse<ServletResponse> profileResponse;
-
+
/** The HttpServletRequest. */
protected HttpServletRequest servletRequest;
-
+
/** The HttpServletResponse. */
protected HttpServletResponse servletResponse;
-
+
/** The SAML 2.0 AuthnRequest. */
protected AuthnRequest authnRequest;
-
+
/** The issuer. */
protected String issuer;
-
+
/** The Subject. */
protected Subject subject;
-
+
/** The Response. */
protected Response response;
-
+
/** The IdP's LoginContext. */
protected LoginContext loginContext;
-
+
/** The RelyingPartyConfiguration. */
protected RelyingPartyConfiguration rpConfig;
-
+
/** The SSOConfiguration. */
protected SSOConfiguration ssoConfig;
-
+
/** The SPSSOConfiguration. */
protected SPSSODescriptor spDescriptor;
-
+
/** The AssertionConsumerService endpoint. */
protected AssertionConsumerService assertionConsumerService;
-
+
public AuthenticationRequestContext() {
}
-
+
public ProfileRequest<ServletRequest> getProfileRequest() {
return profileRequest;
}
-
+
public void setProfileRequest(ProfileRequest<ServletRequest> profileRequest) {
this.profileRequest = profileRequest;
this.servletRequest = (HttpServletRequest) profileRequest.getRawRequest();
}
-
+
public ProfileResponse<ServletResponse> getProfileResponse() {
return profileResponse;
}
-
+
public void setProfileResponse(ProfileResponse<ServletResponse> profileResponse) {
this.profileResponse = profileResponse;
this.servletResponse = (HttpServletResponse) profileResponse.getRawResponse();
}
-
+
public HttpServletRequest getServletRequest() {
return servletRequest;
}
-
+
public void setServletRequest(HttpServletRequest servletRequest) {
this.servletRequest = servletRequest;
}
-
+
public HttpServletResponse getServletResponse() {
return servletResponse;
}
-
+
public void setServletResponse(HttpServletResponse servletResponse) {
this.servletResponse = servletResponse;
}
-
+
public HttpSession getHttpSession() {
-
+
if (getServletRequest() != null) {
return getServletRequest().getSession();
} else {
return null;
}
}
-
+
public AuthnRequest getAuthnRequest() {
return authnRequest;
}
-
+
public void setAuthnRequest(AuthnRequest authnRequest) {
this.authnRequest = authnRequest;
}
-
+
public String getIssuer() {
return issuer;
}
-
+
public void setIssuer(String issuer) {
this.issuer = issuer;
}
-
+
public Subject getSubject() {
return subject;
}
-
+
public void setSubject(Subject subject) {
this.subject = subject;
}
-
+
public LoginContext getLoginContext() {
return loginContext;
}
-
+
public void setLoginContext(LoginContext loginContext) {
this.loginContext = loginContext;
}
-
+
public RelyingPartyConfiguration getRpConfig() {
return rpConfig;
}
-
+
public void setRpConfig(RelyingPartyConfiguration rpConfig) {
this.rpConfig = rpConfig;
}
-
+
public SSOConfiguration getSsoConfig() {
return ssoConfig;
}
-
+
public void setSsoConfig(SSOConfiguration ssoConfig) {
this.ssoConfig = ssoConfig;
}
-
+
public SPSSODescriptor getSpDescriptor() {
return spDescriptor;
}
-
+
public void setSpDescriptor(SPSSODescriptor spDescriptor) {
this.spDescriptor = spDescriptor;
}
-
+
public Response getResponse() {
return response;
}
-
+
public void setResponse(Response response) {
this.response = response;
}
-
+
public AssertionConsumerService getAssertionConsumerService() {
return assertionConsumerService;
}
-
+
public void setAssertionConsumerService(AssertionConsumerService assertionConsumerService) {
this.assertionConsumerService = assertionConsumerService;
}
-
+
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
-
+
if (getClass() != obj.getClass()) {
return false;
}
-
+
final edu.internet2.middleware.shibboleth.idp.profile.saml2.AbstractAuthenticationRequest.AuthenticationRequestContext other = (edu.internet2.middleware.shibboleth.idp.profile.saml2.AbstractAuthenticationRequest.AuthenticationRequestContext) obj;
-
- if (this.profileRequest != other.profileRequest && (this.profileRequest == null || !this.profileRequest.equals(other.profileRequest))) {
+
+ if (this.profileRequest != other.profileRequest
+ && (this.profileRequest == null || !this.profileRequest.equals(other.profileRequest))) {
return false;
}
-
- if (this.profileResponse != other.profileResponse && (this.profileResponse == null || !this.profileResponse.equals(other.profileResponse))) {
+
+ if (this.profileResponse != other.profileResponse
+ && (this.profileResponse == null || !this.profileResponse.equals(other.profileResponse))) {
return false;
}
-
- if (this.servletRequest != other.servletRequest && (this.servletRequest == null || !this.servletRequest.equals(other.servletRequest))) {
+
+ if (this.servletRequest != other.servletRequest
+ && (this.servletRequest == null || !this.servletRequest.equals(other.servletRequest))) {
return false;
}
-
- if (this.servletResponse != other.servletResponse && (this.servletResponse == null || !this.servletResponse.equals(other.servletResponse))) {
+
+ if (this.servletResponse != other.servletResponse
+ && (this.servletResponse == null || !this.servletResponse.equals(other.servletResponse))) {
return false;
}
-
- if (this.authnRequest != other.authnRequest && (this.authnRequest == null || !this.authnRequest.equals(other.authnRequest))) {
+
+ if (this.authnRequest != other.authnRequest
+ && (this.authnRequest == null || !this.authnRequest.equals(other.authnRequest))) {
return false;
}
-
+
if (this.issuer != other.issuer && (this.issuer == null || !this.issuer.equals(other.issuer))) {
return false;
}
-
+
if (this.subject != other.subject && (this.subject == null || !this.subject.equals(other.subject))) {
return false;
}
-
+
if (this.response != other.response && (this.response == null || !this.response.equals(other.response))) {
return false;
}
-
- if (this.loginContext != other.loginContext && (this.loginContext == null || !this.loginContext.equals(other.loginContext))) {
+
+ if (this.loginContext != other.loginContext
+ && (this.loginContext == null || !this.loginContext.equals(other.loginContext))) {
return false;
}
-
+
if (this.rpConfig != other.rpConfig && (this.rpConfig == null || !this.rpConfig.equals(other.rpConfig))) {
return false;
}
-
- if (this.ssoConfig != other.ssoConfig && (this.ssoConfig == null || !this.ssoConfig.equals(other.ssoConfig))) {
+
+ if (this.ssoConfig != other.ssoConfig
+ && (this.ssoConfig == null || !this.ssoConfig.equals(other.ssoConfig))) {
return false;
}
-
- if (this.spDescriptor != other.spDescriptor && (this.spDescriptor == null || !this.spDescriptor.equals(other.spDescriptor))) {
+
+ if (this.spDescriptor != other.spDescriptor
+ && (this.spDescriptor == null || !this.spDescriptor.equals(other.spDescriptor))) {
return false;
}
-
- if (this.assertionConsumerService != other.assertionConsumerService && (this.assertionConsumerService == null || !this.assertionConsumerService.equals(other.assertionConsumerService))) {
+
+ if (this.assertionConsumerService != other.assertionConsumerService
+ && (this.assertionConsumerService == null || !this.assertionConsumerService
+ .equals(other.assertionConsumerService))) {
return false;
}
-
+
return true;
}
-
+
public int hashCode() {
int hash = 7;
return hash;
}
-
-
+
}
-
-
+
/** Class logger. */
private static final Logger log = Logger.getLogger(AbstractAuthenticationRequest.class);
-
+
/** HttpSession key for the AuthenticationRequestContext. */
protected static final String REQUEST_CONTEXT_SESSION_KEY = "edu.internet2.middleware.shibboleth.idp.profile.saml2.AuthenticationRequestContext";
-
+
/** The path to the IdP's AuthenticationManager servlet */
protected String authnMgrURL;
-
+
/** AuthenticationManager to be used */
protected AuthenticationManager authnMgr;
-
+
/** A pool of XML parsers. */
protected ParserPool parserPool;
-
+
/** Builder for AuthnStatements. */
protected SAMLObjectBuilder<AuthnStatement> authnStatementBuilder;
-
+
/** Builder for AuthnContexts. */
protected SAMLObjectBuilder<AuthnContext> authnContextBuilder;
-
+
/** Builder for AuthnContextDeclRef's */
protected SAMLObjectBuilder<AuthnContextDeclRef> authnContextDeclRefBuilder;
-
+
/** Builder for AuthnContextClassRef's. */
protected SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder;
-
+
/**
* Constructor.
*/
public AbstractAuthenticationRequest() {
-
+
parserPool = new BasicParserPool();
- authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>) getBuilderFactory().getBuilder(AuthnStatement.DEFAULT_ELEMENT_NAME);
- authnContextBuilder = (SAMLObjectBuilder<AuthnContext>) getBuilderFactory().getBuilder(AuthnContext.DEFAULT_ELEMENT_NAME);
- authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory().getBuilder(AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
- authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) getBuilderFactory().getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+ authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>) getBuilderFactory().getBuilder(
+ AuthnStatement.DEFAULT_ELEMENT_NAME);
+ authnContextBuilder = (SAMLObjectBuilder<AuthnContext>) getBuilderFactory().getBuilder(
+ AuthnContext.DEFAULT_ELEMENT_NAME);
+ authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory().getBuilder(
+ AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
+ authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) getBuilderFactory().getBuilder(
+ AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
}
-
+
/**
* Set the Authentication Mananger.
- *
- * @param authnManager
- * The IdP's AuthenticationManager.
+ *
+ * @param authnManager The IdP's AuthenticationManager.
*/
public void setAuthenticationManager(AuthenticationManager authnManager) {
this.authnMgr = authnMgr;
}
-
+
/**
* Evaluate a SAML 2 AuthenticationRequest message.
- *
- * @param authnRequest
- * A SAML 2 AuthenticationRequest
- * @param issuer
- * The issuer of the authnRequest.
- * @param session
- * The HttpSession of the request.
- * @param relyingParty
- * The RelyingPartyConfiguration for the request.
- * @param ssoConfig
- * The SSOConfiguration for the request.
- * @param spDescriptor
- * The SPSSODescriptor for the request.
- *
- * @throws ProfileException
- * On Error.
+ *
+ * @param authnRequest A SAML 2 AuthenticationRequest
+ * @param issuer The issuer of the authnRequest.
+ * @param session The HttpSession of the request.
+ * @param relyingParty The RelyingPartyConfiguration for the request.
+ * @param ssoConfig The SSOConfiguration for the request.
+ * @param spDescriptor The SPSSODescriptor for the request.
+ *
+ * @throws ProfileException On Error.
*/
protected void evaluateRequest(final AuthenticationRequestContext requestContext) throws ProfileException {
-
+
Response samlResponse;
-
+
final AuthnRequest authnRequest = requestContext.getAuthnRequest();
String issuer = requestContext.getIssuer();
final HttpSession session = requestContext.getHttpSession();
final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
final SSOConfiguration ssoConfig = requestContext.getSsoConfig();
final SPSSODescriptor spDescriptor = requestContext.getSpDescriptor();
-
+
LoginContext loginCtx = requestContext.getLoginContext();
if (loginCtx.getAuthenticationOK()) {
-
+
// the user successfully authenticated.
// build an authentication assertion.
- samlResponse = buildResponse(authnRequest.getID(), new DateTime(),
- relyingParty.getProviderId(), buildStatus(StatusCode.SUCCESS_URI, null, null));
-
+ samlResponse = buildResponse(authnRequest.getID(), new DateTime(), relyingParty.getProviderId(),
+ buildStatus(StatusCode.SUCCESS_URI, null, null));
+
DateTime now = new DateTime();
Assertion assertion = buildAssertion(now, relyingParty, (AbstractSAML2ProfileConfiguration) ssoConfig);
assertion.setSubject(requestContext.getSubject());
setAuthenticationStatement(assertion, loginCtx, authnRequest);
samlResponse.getAssertions().add(assertion);
-
+
} else {
-
+
// if authentication failed, encode the appropriate SAML error message.
String failureMessage = loginCtx.getAuthenticationFailureMessage();
Status failureStatus = buildStatus(StatusCode.RESPONDER_URI, StatusCode.AUTHN_FAILED_URI, failureMessage);
samlResponse = buildResponse(authnRequest.getID(), new DateTime(), relyingParty.getProviderId(),
failureStatus);
}
-
+
requestContext.setResponse(samlResponse);
}
-
+
/**
* Build a SAML 2 Response element with basic fields populated.
- *
- * Failure handlers can send the returned response element to the RP.
- * Success handlers should add the assertions before sending it.
- *
- * @param inResponseTo
- * The ID of the request this is in response to.
- * @param issueInstant
- * The timestamp of this response.
- * @param issuer
- * The URI of the RP issuing the response.
- * @param status
- * The response's status code.
- *
+ *
+ * Failure handlers can send the returned response element to the RP. Success handlers should add the assertions
+ * before sending it.
+ *
+ * @param inResponseTo The ID of the request this is in response to.
+ * @param issueInstant The timestamp of this response.
+ * @param issuer The URI of the RP issuing the response.
+ * @param status The response's status code.
+ *
* @return The populated Response object.
*/
- protected Response buildResponse(String inResponseTo,
- final DateTime issueInstant, String issuer, final Status status) {
-
+ protected Response buildResponse(String inResponseTo, final DateTime issueInstant, String issuer,
+ final Status status) {
+
Response response = getResponseBuilder().buildObject();
-
+
Issuer i = getIssuerBuilder().buildObject();
i.setValue(issuer);
-
+
response.setVersion(SAML_VERSION);
response.setID(getIdGenerator().generateIdentifier());
response.setInResponseTo(inResponseTo);
response.setIssueInstant(issueInstant);
response.setIssuer(i);
response.setStatus(status);
-
+
return response;
}
-
+
/**
* Check if the user has already been authenticated.
- *
- * @param httpSession
- * the user's HttpSession.
- *
- * @return <code>true</code> if the user has been authenticated. otherwise
- * <code>false</code>
+ *
+ * @param httpSession the user's HttpSession.
+ *
+ * @return <code>true</code> if the user has been authenticated. otherwise <code>false</code>
*/
protected boolean hasUserAuthenticated(final HttpSession httpSession) {
-
+
// if the user has authenticated, their session will have a LoginContext
-
+
Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
return (o != null && o instanceof LoginContext);
}
-
+
/**
- * Check if the user has already been authenticated. If so, return the
- * LoginContext. If not, redirect the user to the AuthenticationManager.
- *
- * @param authnRequest
- * The SAML 2 AuthnRequest.
- * @param httpSession
- * The user's HttpSession.
- * @param request
- * The user's HttpServletRequest.
- * @param response
- * The user's HttpServletResponse.
- *
- * @throws ProfileException
- * on error.
+ * Check if the user has already been authenticated. If so, return the LoginContext. If not, redirect the user to
+ * the AuthenticationManager.
+ *
+ * @param authnRequest The SAML 2 AuthnRequest.
+ * @param httpSession The user's HttpSession.
+ * @param request The user's HttpServletRequest.
+ * @param response The user's HttpServletResponse.
+ *
+ * @throws ProfileException on error.
*/
protected void authenticateUser(final AuthenticationRequestContext requestContext) throws ProfileException {
-
+
AuthnRequest authnRequest = requestContext.getAuthnRequest();
HttpSession httpSession = requestContext.getHttpSession();
HttpServletRequest servletRequest = requestContext.getServletRequest();
HttpServletResponse servletResponse = requestContext.getServletResponse();
-
+
// Forward the request to the AuthenticationManager.
// When the AuthenticationManager is done it will
// forward the request back to this servlet.
-
+
// push the AuthenticationRequestContext into the session so we have it
// for the return leg.
httpSession.setAttribute(REQUEST_CONTEXT_SESSION_KEY, requestContext);
-
+
Saml2LoginContext loginCtx = new Saml2LoginContext(authnRequest);
requestContext.setLoginContext(loginCtx);
loginCtx.setProfileHandlerURL(servletRequest.getRequestURI());
-
+
// the AuthenticationManager expects the LoginContext to be in the HttpSession.
httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginCtx);
try {
- RequestDispatcher dispatcher = servletRequest
- .getRequestDispatcher(authnMgrURL);
- dispatcher.forward(servletRequest,servletResponse);
+ RequestDispatcher dispatcher = servletRequest.getRequestDispatcher(authnMgrURL);
+ dispatcher.forward(servletRequest, servletResponse);
} catch (IOException ex) {
- log.error("Error forwarding SAML 2 AuthnRequest "
- + authnRequest.getID() + " to AuthenticationManager", ex);
- throw new ProfileException("Error forwarding SAML 2 AuthnRequest "
- + authnRequest.getID() + " to AuthenticationManager", ex);
+ log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
+ throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
+ + " to AuthenticationManager", ex);
} catch (ServletException ex) {
- log.error("Error forwarding SAML 2 AuthnRequest "
- + authnRequest.getID() + " to AuthenticationManager", ex);
- throw new ProfileException("Error forwarding SAML 2 AuthnRequest "
- + authnRequest.getID() + " to AuthenticationManager", ex);
+ log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
+ throw new ProfileException("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID()
+ + " to AuthenticationManager", ex);
}
}
-
+
/**
* Build an AuthnStatement and add it to an Assertion.
- *
+ *
* @param assertion An empty SAML 2 Assertion object.
* @param loginContext The processed login context for the AuthnRequest.
* @param authnRequest The AuthnRequest to which this is in response.
- *
+ *
* @throws ProfileException On error.
*/
- protected void setAuthenticationStatement(Assertion assertion,
- final LoginContext loginContext,
+ protected void setAuthenticationStatement(Assertion assertion, final LoginContext loginContext,
final AuthnRequest authnRequest) throws ProfileException {
-
+
// Build the AuthnCtx.
// We need to determine if the user was authenticated
// with an AuthnContextClassRef or a AuthnContextDeclRef
AuthnContext authnCtx = buildAuthnCtx(authnRequest.getRequestedAuthnContext(), loginContext);
if (authnCtx == null) {
- log.error("Error respond to SAML 2 AuthnRequest "
- + authnRequest.getID()
+ log.error("Error respond to SAML 2 AuthnRequest " + authnRequest.getID()
+ " : Unable to determine authentication method");
}
-
+
AuthnStatement stmt = authnStatementBuilder.buildObject();
stmt.setAuthnInstant(loginContext.getAuthenticationInstant());
stmt.setAuthnContext(authnCtx);
-
+
// add the AuthnStatement to the Assertion
List<AuthnStatement> authnStatements = assertion.getAuthnStatements();
authnStatements.add(stmt);
}
-
+
/**
* Create the AuthnContex object.
- *
- * To do this, we have to walk the AuthnRequest's RequestedAuthnContext
- * object and compare any values we find to what's set in the loginContext.
- *
- * @param requestedAuthnCtx
- * The RequestedAuthnContext from the Authentication Request.
- * @param loginContext
- * The processed LoginContext (it must contain the authn method).
- *
+ *
+ * To do this, we have to walk the AuthnRequest's RequestedAuthnContext object and compare any values we find to
+ * what's set in the loginContext.
+ *
+ * @param requestedAuthnCtx The RequestedAuthnContext from the Authentication Request.
+ * @param loginContext The processed LoginContext (it must contain the authn method).
+ *
* @return An AuthnCtx object on success or <code>null</code> on failure.
*/
- protected AuthnContext buildAuthnCtx(
- final RequestedAuthnContext requestedAuthnCtx,
- final LoginContext loginContext) {
-
+ protected AuthnContext buildAuthnCtx(final RequestedAuthnContext requestedAuthnCtx, final LoginContext loginContext) {
+
// this method assumes that only one URI will match.
-
+
AuthnContext authnCtx = authnContextBuilder.buildObject();
String authnMethod = loginContext.getAuthenticationMethod();
-
- List<AuthnContextClassRef> authnClasses = requestedAuthnCtx
- .getAuthnContextClassRefs();
- List<AuthnContextDeclRef> authnDeclRefs = requestedAuthnCtx
- .getAuthnContextDeclRefs();
-
+
+ List<AuthnContextClassRef> authnClasses = requestedAuthnCtx.getAuthnContextClassRefs();
+ List<AuthnContextDeclRef> authnDeclRefs = requestedAuthnCtx.getAuthnContextDeclRefs();
+
if (authnClasses != null) {
for (AuthnContextClassRef classRef : authnClasses) {
if (classRef != null) {
String s = classRef.getAuthnContextClassRef();
if (s != null && authnMethod.equals(s)) {
- AuthnContextClassRef ref = authnContextClassRefBuilder
- .buildObject();
+ AuthnContextClassRef ref = authnContextClassRefBuilder.buildObject();
authnCtx.setAuthnContextClassRef(ref);
return authnCtx;
}
}
}
}
-
+
// if no AuthnContextClassRef's matched, try the DeclRefs
if (authnDeclRefs != null) {
for (AuthnContextDeclRef declRef : authnDeclRefs) {
if (declRef != null) {
String s = declRef.getAuthnContextDeclRef();
if (s != null && authnMethod.equals((s))) {
- AuthnContextDeclRef ref = authnContextDeclRefBuilder
- .buildObject();
+ AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
authnCtx.setAuthnContextDeclRef(ref);
return authnCtx;
}
}
}
}
-
+
// no matches were found.
return null;
}
-
+
/**
* Verify the AuthnRequest is well-formed.
- *
- * @param authnRequest
- * The user's SAML 2 AuthnRequest.
- * @param issuer
- * The Issuer of the AuthnRequest.
- * @param relyingParty
- * The relying party configuration for the request's originator.
- * @param session
- * The user's HttpSession.
- *
- * @throws AuthenticationRequestException
- * on error.
+ *
+ * @param authnRequest The user's SAML 2 AuthnRequest.
+ * @param issuer The Issuer of the AuthnRequest.
+ * @param relyingParty The relying party configuration for the request's originator.
+ * @param session The user's HttpSession.
+ *
+ * @throws AuthenticationRequestException on error.
*/
- protected void verifyAuthnRequest(final AuthenticationRequestContext requestContext) throws AuthenticationRequestException {
-
+ protected void verifyAuthnRequest(final AuthenticationRequestContext requestContext)
+ throws AuthenticationRequestException {
+
final AuthnRequest authnRequest = requestContext.getAuthnRequest();
String issuer = requestContext.getIssuer();
final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
final HttpSession session = requestContext.getHttpSession();
-
+
Status failureStatus;
-
+
// Check if we are in scope to handle this AuthnRequest
checkScope(authnRequest, issuer);
-
+
// verify that the AssertionConsumerService url is valid.
- verifyAssertionConsumerService(requestContext,
- getRelyingPartyConfigurationManager().getMetadataProvider());
-
+ verifyAssertionConsumerService(requestContext, getRelyingPartyConfigurationManager().getMetadataProvider());
+
// check for nameID constraints.
verifySubject(requestContext);
}
-
+
/**
* Get and verify the Subject element.
- *
+ *
* @param requestContext The context for the current request.
*
- * @throws AuthenticationRequestException
- * on error.
+ * @throws AuthenticationRequestException on error.
*/
protected void verifySubject(final AuthenticationRequestContext requestContext)
throws AuthenticationRequestException {
-
+
final AuthnRequest authnRequest = requestContext.getAuthnRequest();
-
+
Status failureStatus;
-
+
Subject subject = authnRequest.getSubject();
-
+
if (subject == null) {
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "SAML 2 AuthnRequest " + authnRequest.getID()
+ failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "SAML 2 AuthnRequest " + authnRequest.getID()
+ " is malformed: It does not contain a Subject.");
- throw new AuthenticationRequestException(
- "AuthnRequest lacks a Subject", failureStatus);
+ throw new AuthenticationRequestException("AuthnRequest lacks a Subject", failureStatus);
}
-
+
// The Web Browser SSO profile disallows SubjectConfirmation
// methods in the requested subject.
- List<SubjectConfirmation> confMethods = subject
- .getSubjectConfirmations();
+ List<SubjectConfirmation> confMethods = subject.getSubjectConfirmations();
if (confMethods != null || confMethods.size() > 0) {
- log
- .error("SAML 2 AuthnRequest "
- + authnRequest.getID()
+ log.error("SAML 2 AuthnRequest " + authnRequest.getID()
+ " is malformed: It contains SubjectConfirmation elements.");
- failureStatus = buildStatus(
- StatusCode.REQUESTER_URI,
- null,
- "SAML 2 AuthnRequest "
- + authnRequest.getID()
+ failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "SAML 2 AuthnRequest " + authnRequest.getID()
+ " is malformed: It contains SubjectConfirmation elements.");
- throw new AuthenticationRequestException(
- "AuthnRequest contains SubjectConfirmation elements",
+ throw new AuthenticationRequestException("AuthnRequest contains SubjectConfirmation elements",
failureStatus);
}
-
+
requestContext.setSubject(subject);
-
+
return;
}
-
+
/**
- * Ensure that metadata can be found for the SP that issued
- * the AuthnRequest.
- *
+ * Ensure that metadata can be found for the SP that issued the AuthnRequest.
+ *
* If found, the request context is updated to reflect the appropriate entries.
- *
+ *
* Before this method may be called, the request context must have an issuer set.
- *
+ *
* @param requestContext The context for the current request.
- *
+ *
* @throws AuthenticationRequestException On error.
*/
- protected void validateRequestAgainstMetadata(final AuthenticationRequestContext requestContext) throws AuthenticationRequestException {
-
+ protected void validateRequestAgainstMetadata(final AuthenticationRequestContext requestContext)
+ throws AuthenticationRequestException {
+
RelyingPartyConfiguration relyingParty = null;
SSOConfiguration ssoConfig = null;
SPSSODescriptor spDescriptor = null;
-
+
// check that we have metadata for the RP
relyingParty = getRelyingPartyConfigurationManager().getRelyingPartyConfiguration(requestContext.getIssuer());
-
+
ProfileConfiguration temp = relyingParty.getProfileConfigurations().get(SSOConfiguration.PROFILE_ID);
if (temp == null) {
- log.error("SAML 2 Authentication Request: No profile configuration registered for " + SSOConfiguration.PROFILE_ID);
- throw new AuthenticationRequestException("No profile configuration registered for " + SSOConfiguration.PROFILE_ID);
+ log.error("SAML 2 Authentication Request: No profile configuration registered for "
+ + SSOConfiguration.PROFILE_ID);
+ throw new AuthenticationRequestException("No profile configuration registered for "
+ + SSOConfiguration.PROFILE_ID);
}
-
+
ssoConfig = (SSOConfiguration) temp;
-
+
try {
- spDescriptor = getMetadataProvider().getEntityDescriptor(
- relyingParty.getRelyingPartyId()).getSPSSODescriptor(
- SAML20_PROTOCOL_URI);
+ spDescriptor = getMetadataProvider().getEntityDescriptor(relyingParty.getRelyingPartyId())
+ .getSPSSODescriptor(SAML20_PROTOCOL_URI);
} catch (MetadataProviderException ex) {
- log.error(
- "SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
+ log.error("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
+ requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, ex);
-
- Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "No metadata available for " + relyingParty.getRelyingPartyId());
-
- throw new AuthenticationRequestException("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, ex, failureStatus);
+
+ Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "No metadata available for "
+ + relyingParty.getRelyingPartyId());
+
+ throw new AuthenticationRequestException(
+ "SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
+ + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, ex, failureStatus);
}
-
+
if (spDescriptor == null) {
log.error("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
+ requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI);
- Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "No metadata available for " + relyingParty.getRelyingPartyId());
-
- throw new AuthenticationRequestException("SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
- + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, failureStatus);
+ Status failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "No metadata available for "
+ + relyingParty.getRelyingPartyId());
+
+ throw new AuthenticationRequestException(
+ "SAML 2 Authentication Request: Unable to locate SPSSODescriptor for SP "
+ + requestContext.getIssuer() + " for protocol " + SAML20_PROTOCOL_URI, failureStatus);
}
-
+
// if all metadata was found, update the request context.
requestContext.setRpConfig(relyingParty);
requestContext.setSsoConfig(ssoConfig);
requestContext.setSpDescriptor(spDescriptor);
}
-
+
/**
* Return the endpoint URL and protocol binding to use for the AuthnRequest.
- *
+ *
* @param requestContext The context for the current request.
*
- * @param metadata
- * The appropriate Metadata.
- *
- * @throws AuthenticationRequestException
- * On error.
+ * @param metadata The appropriate Metadata.
+ *
+ * @throws AuthenticationRequestException On error.
*/
- protected void verifyAssertionConsumerService(
- final AuthenticationRequestContext requestContext,
-
- final MetadataProvider metadata)
- throws AuthenticationRequestException {
-
+ protected void verifyAssertionConsumerService(final AuthenticationRequestContext requestContext,
+
+ final MetadataProvider metadata) throws AuthenticationRequestException {
+
Status failureStatus;
-
+
final AuthnRequest authnRequest = requestContext.getAuthnRequest();
String providerId = requestContext.getRpConfig().getRelyingPartyId();
-
+
// Either the AssertionConsumerServiceIndex must be present
// or AssertionConsumerServiceURL must be present.
-
+
Integer idx = authnRequest.getAssertionConsumerServiceIndex();
String acsURL = authnRequest.getAssertionConsumerServiceURL();
-
+
if (idx != null && acsURL != null) {
log
.error("SAML 2 AuthnRequest "
- + authnRequest.getID()
- + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
+ + authnRequest.getID()
+ + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
failureStatus = buildStatus(
StatusCode.REQUESTER_URI,
null,
"SAML 2 AuthnRequest "
- + authnRequest.getID()
- + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
- throw new AuthenticationRequestException("Malformed AuthnRequest",
- failureStatus);
+ + authnRequest.getID()
+ + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
+ throw new AuthenticationRequestException("Malformed AuthnRequest", failureStatus);
}
-
+
SPSSODescriptor spDescriptor;
try {
- spDescriptor = metadata.getEntityDescriptor(providerId)
- .getSPSSODescriptor(SAML20_PROTOCOL_URI);
+ spDescriptor = metadata.getEntityDescriptor(providerId).getSPSSODescriptor(SAML20_PROTOCOL_URI);
} catch (MetadataProviderException ex) {
- log.error(
- "Unable retrieve SPSSODescriptor metadata for providerId "
- + providerId
- + " while processing SAML 2 AuthnRequest "
- + authnRequest.getID(), ex);
- failureStatus = buildStatus(StatusCode.RESPONDER_URI, null,
- "Unable to locate metadata for " + providerId);
- throw new AuthenticationRequestException(
- "Unable to locate metadata", ex, failureStatus);
+ log.error("Unable retrieve SPSSODescriptor metadata for providerId " + providerId
+ + " while processing SAML 2 AuthnRequest " + authnRequest.getID(), ex);
+ failureStatus = buildStatus(StatusCode.RESPONDER_URI, null, "Unable to locate metadata for " + providerId);
+ throw new AuthenticationRequestException("Unable to locate metadata", ex, failureStatus);
}
-
- List<AssertionConsumerService> acsList = spDescriptor
- .getAssertionConsumerServices();
-
+
+ List<AssertionConsumerService> acsList = spDescriptor.getAssertionConsumerServices();
+
// if the ACS index is specified, retrieve it from the metadata
if (idx != null) {
-
+
int i = idx.intValue();
-
+
// if the index is out of range, return an appropriate error.
if (i > acsList.size()) {
- log.error("Illegal AssertionConsumerIndex specicifed (" + i
- + ") in SAML 2 AuthnRequest " + authnRequest.getID());
-
- failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
- "Illegal AssertionConsumerIndex specicifed (" + i
- + ") in SAML 2 AuthnRequest "
+ log.error("Illegal AssertionConsumerIndex specicifed (" + i + ") in SAML 2 AuthnRequest "
+ authnRequest.getID());
-
- throw new AuthenticationRequestException(
- "Illegal AssertionConsumerIndex in AuthnRequest",
+
+ failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
+ "Illegal AssertionConsumerIndex specicifed (" + i + ") in SAML 2 AuthnRequest "
+ + authnRequest.getID());
+
+ throw new AuthenticationRequestException("Illegal AssertionConsumerIndex in AuthnRequest",
failureStatus);
}
-
+
requestContext.setAssertionConsumerService(acsList.get(i));
return;
}
-
+
// if the ACS endpoint is specified, validate it against the metadata
String protocolBinding = authnRequest.getProtocolBinding();
for (AssertionConsumerService acs : acsList) {
}
}
}
-
- log
- .error("Error processing SAML 2 AuthnRequest message "
- + authnRequest.getID()
- + ": Unable to validate AssertionConsumerServiceURL against metadata: "
- + acsURL + " for binding " + protocolBinding);
-
+
+ log.error("Error processing SAML 2 AuthnRequest message " + authnRequest.getID()
+ + ": Unable to validate AssertionConsumerServiceURL against metadata: " + acsURL + " for binding "
+ + protocolBinding);
+
failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
"Unable to validate AssertionConsumerService against metadata.");
-
+
throw new AuthenticationRequestException(
"SAML 2 AuthenticationRequest: Unable to validate AssertionConsumerService against Metadata",
failureStatus);
}
-
+
/**
- * Check if an {@link AuthnRequest} contains a {@link Scoping} element. If
- * so, check if the specified IdP is in the {@link IDPList} element. If no
- * Scoping element is present, this method returns <code>true</code>.
- *
- * @param authnRequest
- * The {@link AuthnRequest} element to check.
- * @param providerId
- * The IdP's ProviderID.
- *
- * @throws AuthenticationRequestException
- * on error.
+ * Check if an {@link AuthnRequest} contains a {@link Scoping} element. If so, check if the specified IdP is in the
+ * {@link IDPList} element. If no Scoping element is present, this method returns <code>true</code>.
+ *
+ * @param authnRequest The {@link AuthnRequest} element to check.
+ * @param providerId The IdP's ProviderID.
+ *
+ * @throws AuthenticationRequestException on error.
*/
- protected void checkScope(final AuthnRequest authnRequest, String providerId)
- throws AuthenticationRequestException {
-
+ protected void checkScope(final AuthnRequest authnRequest, String providerId) throws AuthenticationRequestException {
+
Status failureStatus;
-
+
List<String> idpEntries = new LinkedList<String>();
-
+
Scoping scoping = authnRequest.getScoping();
if (scoping == null) {
return;
}
-
+
// process all of the explicitly listed idp provider ids
IDPList idpList = scoping.getIDPList();
if (idpList == null) {
return;
}
-
+
List<IDPEntry> explicitIDPEntries = idpList.getIDPEntrys();
if (explicitIDPEntries != null) {
for (IDPEntry entry : explicitIDPEntries) {
}
}
}
-
+
// If the IDPList is incomplete, retrieve the complete list
// and add the entries to idpEntries.
GetComplete getComplete = idpList.getGetComplete();
}
}
}
-
+
// iterate over all the IDPEntries we've gathered,
// and check if we're in scope.
for (String requestProviderId : idpEntries) {
return;
}
}
-
- log.error("SAML 2 AuthnRequest " + authnRequest.getID()
- + " contains a Scoping element which "
+
+ log.error("SAML 2 AuthnRequest " + authnRequest.getID() + " contains a Scoping element which "
+ "does not contain a providerID registered with this IdP.");
-
- failureStatus = buildStatus(StatusCode.RESPONDER_URI,
- StatusCode.NO_SUPPORTED_IDP_URI, null);
- throw new AuthenticationRequestException(
- "Unrecognized providerID in Scoping element", failureStatus);
+
+ failureStatus = buildStatus(StatusCode.RESPONDER_URI, StatusCode.NO_SUPPORTED_IDP_URI, null);
+ throw new AuthenticationRequestException("Unrecognized providerID in Scoping element", failureStatus);
}
-
+
/**
* Retrieve an incomplete IDPlist.
- *
+ *
* This only handles URL-based <GetComplete/> references.
- *
- * @param getComplete
- * The (possibly <code>null</code>) <GetComplete/>
- * element
- *
- * @return an {@link IDPList} or <code>null</code> if the uri can't be
- * dereferenced.
+ *
+ * @param getComplete The (possibly <code>null</code>) <GetComplete/> element
+ *
+ * @return an {@link IDPList} or <code>null</code> if the uri can't be dereferenced.
*/
protected IDPList getCompleteIDPList(final GetComplete getComplete) {
-
+
// XXX: enhance this method to cache the url and last-modified-header
-
+
if (getComplete == null) {
return null;
}
-
+
String uri = getComplete.getGetComplete();
if (uri != null) {
return null;
}
-
+
IDPList idpList = null;
InputStream istream = null;
-
+
try {
URL url = new URL(uri);
URLConnection conn = url.openConnection();
istream = conn.getInputStream();
-
+
// convert the raw data into an XML object
Document doc = parserPool.parse(istream);
Element docElement = doc.getDocumentElement();
- Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory()
- .getUnmarshaller(docElement);
+ Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(docElement);
idpList = (IDPList) unmarshaller.unmarshall(docElement);
-
+
} catch (MalformedURLException ex) {
- log.error(
- "Unable to retrieve GetComplete IDPList. Unsupported URI: "
- + uri, ex);
+ log.error("Unable to retrieve GetComplete IDPList. Unsupported URI: " + uri, ex);
} catch (IOException ex) {
- log.error("IO Error while retreieving GetComplete IDPList from "
- + uri, ex);
+ log.error("IO Error while retreieving GetComplete IDPList from " + uri, ex);
} catch (XMLParserException ex) {
- log.error(
- "Internal OpenSAML error while parsing GetComplete IDPList from "
- + uri, ex);
+ log.error("Internal OpenSAML error while parsing GetComplete IDPList from " + uri, ex);
} catch (UnmarshallingException ex) {
- log.error(
- "Internal OpenSAML error while unmarshalling GetComplete IDPList from "
- + uri, ex);
+ log.error("Internal OpenSAML error while unmarshalling GetComplete IDPList from " + uri, ex);
} finally {
-
+
if (istream != null) {
try {
istream.close();
}
}
}
-
+
return idpList;
}
-
+
/**
* Encode a SAML Response.
- *
+ *
* @param binding The SAML protocol binding to use.
* @param requestContext The context for the request.
- *
+ *
* @throws ProfileException On error.
*/
- protected void encodeResponse(String binding,
- final AuthenticationRequestContext requestContext) throws ProfileException {
-
+ protected void encodeResponse(String binding, final AuthenticationRequestContext requestContext)
+ throws ProfileException {
+
final ProfileResponse<ServletResponse> profileResponse = requestContext.getProfileResponse();
final Response samlResponse = requestContext.getResponse();
final RelyingPartyConfiguration relyingParty = requestContext.getRpConfig();
final RoleDescriptor roleDescriptor = requestContext.getSpDescriptor();
final Endpoint endpoint = requestContext.getAssertionConsumerService();
-
-
+
MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(binding);
if (encoder == null) {
log.error("No MessageEncoder registered for " + binding);
throw new ProfileException("No MessageEncoder registered for " + binding);
}
-
+
encoder.setResponse(profileResponse.getRawResponse());
encoder.setIssuer(relyingParty.getProviderId());
encoder.setMetadataProvider(getRelyingPartyConfigurationManager().getMetadataProvider());
encoder.setSigningCredential(relyingParty.getDefaultSigningCredential());
encoder.setSamlMessage(samlResponse);
encoder.setRelyingPartyEndpoint(endpoint);
-
+
try {
encoder.encode();
} catch (BindingException ex) {
throw new ProfileException("Unable to encode response the relying party: "
+ relyingParty.getRelyingPartyId(), ex);
}
-
+
}
-
+
}
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLVersion;
import org.opensaml.common.impl.SAMLObjectContentReference;
+import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.log.Level;
import org.opensaml.saml2.core.Advice;
import org.opensaml.saml2.core.Assertion;
/** SAML Version for this profile handler. */
public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
- /** URI for the SAML 2 protocol. */
- public static final String SAML20_PROTOCOL_URI = "urn:oasis:names:tc:SAML:2.0:protocol";
-
/** Class logger. */
private Logger log = Logger.getLogger(AbstractSAML2ProfileHandler.class);
RoleDescriptor relyingPartyRole;
try {
relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
- requestContext.getRelyingPartyRole(), SAML20_PROTOCOL_URI);
+ requestContext.getRelyingPartyRole(), SAMLConstants.SAML20P_NS);
} catch (MetadataProviderException e) {
throw new ProfileException("Unable to lookup entity metadata for relying party "
+ requestContext.getRelyingPartyId());
+ "/" + requestContext.getRelyingPartyId());
}
Map<String, BaseAttribute> principalAttributes = requestContext.getPrincipalAttributes();
- List<String> supportedNameFormats = getNameIDFormat(requestContext);
+ List<String> supportedNameFormats = getNameFormats(requestContext);
if (log.isDebugEnabled()) {
log.debug("Supported NameID formats: " + supportedNameFormats);
*
* @throws ProfileException thrown if there is a problem determing the NameID format to use
*/
- protected List<String> getNameIDFormat(SAML2ProfileRequestContext requestContext) throws ProfileException {
+ protected List<String> getNameFormats(SAML2ProfileRequestContext requestContext) throws ProfileException {
ArrayList<String> nameFormats = new ArrayList<String>();
try {
RoleDescriptor assertingPartyRole = getMetadataProvider().getRole(requestContext.getAssertingPartyId(),
- requestContext.getAssertingPartyRole(), SAML20_PROTOCOL_URI);
+ requestContext.getAssertingPartyRole(), SAMLConstants.SAML20P_NS);
List<String> assertingPartySupportedFormats = getEntitySupportedFormats(assertingPartyRole);
String nameFormat = null;
if (nameFormats.isEmpty()) {
RoleDescriptor relyingPartyRole = getMetadataProvider().getRole(requestContext.getRelyingPartyId(),
- requestContext.getRelyingPartyRole(), SAML20_PROTOCOL_URI);
+ requestContext.getRelyingPartyRole(), SAMLConstants.SAML20P_NS);
List<String> relyingPartySupportedFormats = getEntitySupportedFormats(relyingPartyRole);
assertingPartySupportedFormats.retainAll(relyingPartySupportedFormats);
import org.opensaml.common.binding.decoding.MessageDecoder;
import org.opensaml.common.binding.encoding.MessageEncoder;
import org.opensaml.common.binding.security.SAMLSecurityPolicy;
+import org.opensaml.saml2.binding.decoding.HTTPSOAP11Decoder;
import org.opensaml.saml2.core.AttributeQuery;
import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.NameID;
if (log.isDebugEnabled()) {
log.debug("Decoding incomming request");
}
- MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(BINDING);
+ MessageDecoder<ServletRequest> decoder = getMessageDecoderFactory().getMessageDecoder(
+ HTTPSOAP11Decoder.BINDING_URI);
if (decoder == null) {
- throw new ProfileException("No request decoder was registered for binding type: " + BINDING);
+ throw new ProfileException("No request decoder was registered for binding type: "
+ + HTTPSOAP11Decoder.BINDING_URI);
}
super.populateMessageDecoder(decoder);
+++ /dev/null
-/*
- * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package edu.internet2.middleware.shibboleth.idp.profile.saml2;
-
-import org.opensaml.saml2.core.Status;
-
-/**
- * Indicates an error while processing an {@link AuthenticationRequest}.
- */
-public class AuthenticationRequestException extends java.lang.Exception {
-
- protected Status status = null;
-
- /**
- * Get the SAML 2 Status, if any, associated with this error.
- *
- * @return A SAML 2 Status object, or <code>null</code> if none was set.
- */
- public Status getStatus() {
- return status;
- }
-
- /**
- * Creates a new instance of <code>AuthenticationRequestException</code>
- * without detail message.
- */
- public AuthenticationRequestException() {
- }
-
- /**
- * Constructs an instance of <code>AuthenticationRequestException</code>
- * with the specified detail message.
- *
- * @param message
- * The detail message.
- */
- public AuthenticationRequestException(final String message) {
- super(message);
- }
-
- /**
- * Constructs an instance of <code>AuthenticationRequestException</code>
- * with the specified detail message.
- *
- * @param message
- * The detail message.
- * @param status
- * A SAML 2 Status indicated which error should be returned to
- * the requestor.
- */
- public AuthenticationRequestException(final String message,
- final Status status) {
- super(message);
- this.status = status;
- }
-
- /**
- * Constructs an instance of <code>AuthenticationRequestException</code>
- * with the specified cause and a detail message of
- * <code>(cause==null ? null : cause.toString())</code> (which typically
- * contains the class and detail message of cause). This constructor is
- * useful for exceptions that are little more than wrappers for other
- * throwables (for example, {@link PrivilegedActionException}).
- *
- * @param cause
- * The cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code>
- * is permitted, and indicates that the cause is nonexistent or
- * unknown.)
- */
- public AuthenticationRequestException(final Throwable cause) {
- super(cause);
- }
-
- /**
- * Constructs an instance of <code>AuthenticationRequestException</code>
- * with the specified cause and a detail message of
- * <code>(cause==null ? null : cause.toString())</code> (which typically
- * contains the class and detail message of cause). This constructor is
- * useful for exceptions that are little more than wrappers for other
- * throwables (for example, {@link PrivilegedActionException}).
- *
- * @param cause
- * The cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code>
- * is permitted, and indicates that the cause is nonexistent or
- * unknown.)
- * @param code
- * A SAML 2 Status indicated which error should be returned to
- * the requestor.
- */
- public AuthenticationRequestException(final Throwable cause,
- final Status status) {
- super(cause);
- this.status = status;
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- *
- * Note that the detail message associated with cause is not automatically
- * incorporated in this exception's detail message.
- *
- * @param message
- * The detail message (which is saved for later retrieval by the
- * {@link Throwable#getMessage()} method).
- * @param cause
- * The cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code>
- * is permitted, and indicates that the cause is nonexistent or
- * unknown.)
- */
- public AuthenticationRequestException(final String message,
- final Throwable cause) {
- super(message, cause);
- }
-
- /**
- * Constructs a new exception with the specified detail message and cause.
- *
- * Note that the detail message associated with cause is not automatically
- * incorporated in this exception's detail message.
- *
- * @param message
- * The detail message (which is saved for later retrieval by the
- * {@link Throwable#getMessage()} method).
- * @param cause
- * The cause (which is saved for later retrieval by the
- * {@link Throwable#getCause()} method). (A <code>null</code>
- * is permitted, and indicates that the cause is nonexistent or
- * unknown.)
- * @param code
- * A SAML 2 Status indicated which error should be returned to
- * the requestor.
- */
- public AuthenticationRequestException(final String message,
- final Throwable cause, final Status code) {
- super(message, cause);
- this.status = status;
- }
-
-}
--- /dev/null
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.profile.saml2;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Response;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.SSOConfiguration;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+
+/**
+ * SAML 2.0 authentication request profile handler.
+ */
+public class AuthenticationRequestProfileHandler extends AbstractSAML2ProfileHandler {
+
+ /** {@inheritDoc} */
+ public String getProfileId() {
+ return "urn:mace:shibboleth:2.0:idp:profiles:saml2:request:authentication";
+ }
+
+ /** {@inheritDoc} */
+ public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
+ throws ProfileException {
+
+ }
+
+ /**
+ * Represents the internal state of a SAML 2.0 Authentiation Request while it's being processed by the IdP.
+ */
+ protected class AuthenticationRequestContext extends
+ SAML2ProfileRequestContext<AuthnRequest, Response, SSOConfiguration> {
+
+ /** The IdP's LoginContext. */
+ private LoginContext loginContext;
+
+ /**
+ * Constructor.
+ *
+ * @param request current profile request
+ * @param response current profile response
+ */
+ public AuthenticationRequestContext(ProfileRequest<ServletRequest> request,
+ ProfileResponse<ServletResponse> response) {
+ super(request, response);
+ }
+
+ /**
+ * Gets the login context for this request.
+ *
+ * @return login context for this request
+ */
+ public LoginContext getLoginContext() {
+ return loginContext;
+ }
+
+ /**
+ * Sets the login context for this request.
+ *
+ * @param context login context for this request
+ */
+ public void setLoginContext(LoginContext context) {
+ loginContext = context;
+ }
+ }
+}
\ No newline at end of file