second draft of authn request; clean up abstract profile handler a bit
authordmorr <dmorr@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 30 Mar 2007 17:56:26 +0000 (17:56 +0000)
committerdmorr <dmorr@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 30 Mar 2007 17:56:26 +0000 (17:56 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@2168 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AbstractProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AuthenticationRequest.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AuthenticationRequestException.java [new file with mode: 0644]

index 6240a53..e3ac727 100644 (file)
@@ -21,12 +21,17 @@ import javax.servlet.ServletResponse;
 
 import org.apache.log4j.Logger;
 import org.opensaml.Configuration;
+import org.opensaml.common.IdentifierGenerator;
 import org.opensaml.common.SAMLObject;
 import org.opensaml.common.SAMLVersion;
 import org.opensaml.common.binding.BindingException;
 import org.opensaml.common.binding.MessageDecoder;
 import org.opensaml.common.binding.MessageEncoder;
 import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusMessage;
 import org.opensaml.saml2.encryption.Encrypter;
 import org.opensaml.saml2.metadata.provider.MetadataProvider;
 import org.opensaml.xml.XMLObjectBuilderFactory;
@@ -41,226 +46,367 @@ import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfi
  */
 public abstract class AbstractProfileHandler implements ProfileHandler {
 
-    /** SAML Version for this profile handler. */
-    public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
-
-    /** Class logger. */
-    private static Logger log = Logger.getLogger(AbstractProfileHandler.class);
-
-    /** For building XML. */
-    private XMLObjectBuilderFactory builderFactory;
-
-    /** For generating random ids. */
-    private SecureRandomIdentifierGenerator idGenerator;
-
-    /** For decoding requests. */
-    private MessageDecoder<ServletRequest> decoder;
-
-    /** For encoding responses. */
-    private MessageEncoder<ServletResponse> encoder;
-
-    /** Relying party configuration. */
-    private RelyingPartyConfiguration relyingPartyConfiguration;
-
-    /** For resolving attributes. */
-    private AttributeResolver resolver;
-
-    /** To determine releasable attributes. */
-    private FilteringEngine engine;
-
-    /** Attribute metadata provider. */
-    private MetadataProvider provider;
-
-    /** For encrypting XML. */
-    private Encrypter encrypter;
-
-    /**
-     * Default constructor.
-     */
-    public AbstractProfileHandler() {
-        builderFactory = Configuration.getBuilderFactory();
-        idGenerator = new SecureRandomIdentifierGenerator();
-    }
-
-    /**
-     * Returns the XML builder factory.
-     * 
-     * @return Returns the builderFactory.
-     */
-    public XMLObjectBuilderFactory getBuilderFactory() {
-        return builderFactory;
-    }
-
-    /**
-     * Returns the id generator.
-     * 
-     * @return Returns the idGenerator.
-     */
-    public SecureRandomIdentifierGenerator getIdGenerator() {
-        return idGenerator;
-    }
-
-    /**
-     * Sets the decoder.
-     * 
-     * @param d <code>MessageDecoder</code>
-     */
-    public void setDecoder(MessageDecoder<ServletRequest> d) {
-        decoder = d;
-    }
-
-    /**
-     * Returns the decoder.
-     * 
-     * @return <code>MessageDecoder</code>
-     */
-    public MessageDecoder<ServletRequest> getDecoder() {
-        return decoder;
-    }
-
-    /**
-     * Sets the encoder.
-     * 
-     * @param e <code>MessageEncoder</code>
-     */
-    public void setEncoder(MessageEncoder<ServletResponse> e) {
-        encoder = e;
-    }
-
-    /**
-     * Returns the encoder.
-     * 
-     * @return <code>MessageEncoder</code>
-     */
-    public MessageEncoder<ServletResponse> getEncoder() {
-        return encoder;
-    }
-
-    /**
-     * Sets the attribute resolver.
-     * 
-     * @param r <code>AttributeResolver</code>
-     */
-    public void setAttributeResolver(AttributeResolver r) {
-        resolver = r;
-    }
-
-    /**
-     * Returns the attribute resolver.
-     * 
-     * @return <code>AttributeResolver</code>
-     */
-    public AttributeResolver getAttributeResolver() {
-        return resolver;
-    }
-
-    /**
-     * Sets the filter engine.
-     * 
-     * @param e <code>FilterEngine</code>
-     */
-    public void setFilterEngine(FilteringEngine e) {
-        engine = e;
-    }
-
-    /**
-     * Returns the filter engine.
-     * 
-     * @return <code>FilterEngine</code>
-     */
-    public FilteringEngine getFilteringEngine() {
-        return engine;
-    }
-
-    /**
-     * Sets the metadata provider.
-     * 
-     * @param p <code>MetadataProvider</code>
-     */
-    public void setMetadataProvider(MetadataProvider p) {
-        provider = p;
-    }
-
-    /**
-     * Returns the metadata provider.
-     * 
-     * @return <code>MetadataProvider</code>
-     */
-    public MetadataProvider getMetadataProvider() {
-        return provider;
-    }
-
-    /**
-     * Returns the relying party configuration.
-     * 
-     * @return Returns the relyingParty.
-     */
-    public RelyingPartyConfiguration getRelyingPartyConfiguration() {
-        return relyingPartyConfiguration;
-    }
-
-    /**
-     * Sets the relying party configuration.
-     * 
-     * @param c The relyingParty to set.
-     */
-    public void setRelyingPartyConfiguration(RelyingPartyConfiguration c) {
-        relyingPartyConfiguration = c;
-    }
-
-    /**
-     * Returns the encrypter.
-     * 
-     * @return Returns the encrypter.
-     */
-    public Encrypter getEncrypter() {
-        return encrypter;
-    }
-
-    /**
-     * Sets the encrypter.
-     * 
-     * @param e The encrypter to set.
-     */
-    public void setEncrypter(Encrypter e) {
-        encrypter = e;
-    }
-
-    /**
-     * This decodes the attribute query message from the supplied request.
-     * 
-     * @param request <code>ServletRequest</code>
-     * @return <code>SAMLObject</code>
-     * @throws BindingException if the request cannot be decoded
-     */
-    protected SAMLObject decodeMessage(ServletRequest request) throws BindingException {
-        // call decode method on decoder
-        decoder.setRequest(request);
-        decoder.decode();
-        if (log.isDebugEnabled()) {
-            log.debug("decoded servlet request");
-        }
-
-        // get SAMLMessage from the decoder
-        final SAMLObject message = decoder.getSAMLMessage();
-        if (log.isDebugEnabled()) {
-            log.debug("retrieved attribute query message from decoder: " + message);
-        }
-
-        return message;
-    }
-
-    /**
-     * This encodes the supplied response.
-     * 
-     * @param response <code>SAMLObject</code>
-     * @throws BindingException if the response cannot be encoded
-     */
-    protected void encodeResponse(SAMLObject response) throws BindingException {
-        encoder.setSAMLMessage(response);
-        encoder.encode();
-        if (log.isDebugEnabled()) {
-            log.debug("encoded saml1 response");
-        }
-    }
+       /** SAML Version for this profile handler. */
+       public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
+
+       /** Class logger. */
+       private static Logger log = Logger.getLogger(AbstractProfileHandler.class);
+
+       /** For building XML. */
+       private XMLObjectBuilderFactory builderFactory;
+
+       /** For generating random ids. */
+       private IdentifierGenerator idGenerator;
+
+       /** For decoding requests. */
+       private MessageDecoder<ServletRequest> decoder;
+
+       /** For encoding responses. */
+       private MessageEncoder<ServletResponse> encoder;
+
+       /** For resolving attributes. */
+       private AttributeResolver resolver;
+
+       /** To determine releasable attributes. */
+       private FilteringEngine engine;
+
+       /** For encrypting XML. */
+       private Encrypter encrypter;
+
+       /** Builder for Response elements. */
+       protected XMLObjectBuilder responseBuilder;
+
+       /** Builder for Status elements. */
+       private XMLObjectBuilder statusBuilder;
+
+       /** Builder for StatusCode elements. */
+       private XMLObjectBuilder statusCodeBuilder;
+
+       /** Builder for StatusMessage elements. */
+       private XMLObjectBuilder statusMessageBuilder;
+
+       /** Builder for Issuer elements. */
+       protected XMLObjectBuilder issuerBuilder;
+
+       /**
+        * Default constructor.
+        */
+       public AbstractProfileHandler() {
+               builderFactory = Configuration.getBuilderFactory();
+               idGenerator = new SecureRandomIdentifierGenerator();
+
+               responseBuilder = builderFactory
+                               .getBuilder(Response.DEFAULT_ELEMENT_NAME);
+               statusBuilder = builderFactory.getBuilder(Status.DEFAILT_ELEMENT_NAME);
+               statusCodeBuilder = builderFactory
+                               .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
+               statusMessageBuilder = builderFactory
+                               .getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
+               issuerBuilder = builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
+       }
+
+       /**
+        * Returns the XML builder factory.
+        * 
+        * @return Returns the builderFactory.
+        */
+       public XMLObjectBuilderFactory getBuilderFactory() {
+               return builderFactory;
+       }
+
+       /**
+        * Returns the id generator.
+        * 
+        * @return Returns the idGenerator.
+        */
+       public SecureRandomIdentifierGenerator getIdGenerator() {
+               return idGenerator;
+       }
+
+       /**
+        * Sets the decoder.
+        * 
+        * @param d
+        *            <code>MessageDecoder</code>
+        */
+       public void setDecoder(MessageDecoder<ServletRequest> d) {
+               decoder = d;
+       }
+
+       /**
+        * Returns the decoder.
+        * 
+        * @return <code>MessageDecoder</code>
+        */
+       public MessageDecoder<ServletRequest> getDecoder() {
+               return decoder;
+       }
+
+       /**
+        * Sets the encoder.
+        * 
+        * @param e
+        *            <code>MessageEncoder</code>
+        */
+       public void setEncoder(MessageEncoder<ServletResponse> e) {
+               encoder = e;
+       }
+
+       /**
+        * Returns the encoder.
+        * 
+        * @return <code>MessageEncoder</code>
+        */
+       public MessageEncoder<ServletResponse> getEncoder() {
+               return encoder;
+       }
+
+       /**
+        * Sets the attribute resolver.
+        * 
+        * @param r
+        *            <code>AttributeResolver</code>
+        */
+       public void setAttributeResolver(AttributeResolver r) {
+               resolver = r;
+       }
+
+       /**
+        * Returns the attribute resolver.
+        * 
+        * @return <code>AttributeResolver</code>
+        */
+       public AttributeResolver getAttributeResolver() {
+               return resolver;
+       }
+
+       /**
+        * Sets the filter engine.
+        * 
+        * @param e
+        *            <code>FilterEngine</code>
+        */
+       public void setFilterEngine(FilteringEngine e) {
+               engine = e;
+       }
+
+       /**
+        * Returns the filter engine.
+        * 
+        * @return <code>FilterEngine</code>
+        */
+       public FilteringEngine getFilteringEngine() {
+               return engine;
+       }
+
+       /**
+        * Sets the metadata provider.
+        * 
+        * @param p
+        *            <code>MetadataProvider</code>
+        */
+       public void setMetadataProvider(MetadataProvider p) {
+               provider = p;
+       }
+
+       /**
+        * Returns the metadata provider.
+        * 
+        * @return <code>MetadataProvider</code>
+        */
+       public MetadataProvider getMetadataProvider() {
+               return provider;
+       }
+
+       /**
+        * Returns the relying party configuration.
+        * 
+        * @return Returns the relyingParty.
+        */
+       public RelyingPartyConfiguration getRelyingPartyConfiguration() {
+               return relyingPartyConfiguration;
+       }
+
+       /**
+        * Sets the relying party configuration.
+        * 
+        * @param c
+        *            The relyingParty to set.
+        */
+       public void setRelyingPartyConfiguration(RelyingPartyConfiguration c) {
+               relyingPartyConfiguration = c;
+       }
+
+       /**
+        * Returns the encrypter.
+        * 
+        * @return Returns the encrypter.
+        */
+       public Encrypter getEncrypter() {
+               return encrypter;
+       }
+
+       /**
+        * Sets the encrypter.
+        * 
+        * @param e
+        *            The encrypter to set.
+        */
+       public void setEncrypter(Encrypter e) {
+               encrypter = e;
+       }
+
+       /**
+        * This decodes the attribute query message from the supplied request.
+        * 
+        * @param request
+        *            <code>ServletRequest</code>
+        * @return <code>SAMLObject</code>
+        * @throws BindingException
+        *             if the request cannot be decoded
+        */
+       protected SAMLObject decodeMessage(ServletRequest request)
+                       throws BindingException {
+
+               decoder.setRequest(request);
+               decoder.decode();
+               if (log.isDebugEnabled()) {
+                       log.debug("decoded servlet request");
+               }
+
+               return decoder.getSAMLMessage();
+               ;
+       }
+
+       /**
+        * This encodes the supplied response.
+        * 
+        * @param response
+        *            <code>SAMLObject</code>
+        * @throws BindingException
+        *             if the response cannot be encoded
+        */
+       protected void encodeResponse(SAMLObject response) throws BindingException {
+
+               encoder.setSAMLMessage(response);
+               encoder.encode();
+       }
+
+       /**
+        * Build a status message, with an optional second-level failure message.
+        * 
+        * @param topLevelCode
+        *            The top-level status code. Should be from saml-core-2.0-os,
+        *            sec. 3.2.2.2
+        * @param secondLevelCode
+        *            An optional second-level failure code. Should be from
+        *            saml-core-2.0-is, sec 3.2.2.2. If null, no second-level Status
+        *            element will be set.
+        * @param secondLevelFailureMessage
+        *            An optional second-level failure message.
+        * 
+        * @return a Status object.
+        */
+       protected Status buildStatus(String topLevelCode, String secondLevelCode,
+                       String secondLevelFailureMessage) {
+
+               Status status = (Status) statusBuilder
+                               .buildObject(Status.DEFAULT_ELEMENT_NAME);
+               StatusCode statusCode = (StatusCode) statusCodeBuilder
+                               .buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
+
+               statusCode.setValue(topLevelCode);
+               if (secondLevelCode != null) {
+                       StatusCode secondLevelStatusCode = (StatusCode) statusCodeBuilder
+                                       .buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
+                       secondLevelStatusCode.setValue(secondLevelCode);
+                       statusCode.setStatusCode(secondLevelStatusCode);
+               }
+
+               if (secondLevelFailureMessage != null) {
+                       StatusMessage msg = (StatusMessage) statusMessageBuilder
+                                       .buildObject(StatusMessage.DEFAULT_ELEMENT_NAME);
+                       msg.setMessage(secondLevelFailureMessage);
+                       status.setMessage(msg);
+               }
+
+               return status;
+       }
+
+       /**
+        * 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 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, String issuer,
+                       final Status status) {
+
+               Response response = (Response) responseBuilder
+                               .buildObject(Response.DEFAULT_ELEMENT_NAME);
+
+               Issuer i = (Issuer) issuerBuilder
+                               .buildObject(Issuer.DEFAULT_ELEMENT_NAME);
+               i.setValue(issuer);
+
+               response.setVersion(SAML_VERSION);
+               response.setId(getIdGenerator().generateIdentifier());
+               response.setInResponseto(inResponseTo);
+               response.setIssueInstance(new DateTime());
+               response.setIssuer(i);
+               response.setStatus(status);
+
+               return response;
+       }
+
+       protected Assertion buildAssertion(final Subjcet subject,
+                       final Conditions conditions, String issuer, final String[] audiences) {
+
+               Assertion assertion = (Assertion) assertionBuilder
+                               .buildObject(Assertion.DEFAULT_ELEMENT_NAME);
+               assertion.setID(getIdGenerator().generateIdentifier());
+               assertion.setVersion(SAML_VERSION);
+               assertion.setIssueInstant(new DateTime());
+               assertion.setConditions(conditions);
+               assertion.setSubject(subject);
+
+               Issuer i = (Issuer) issuerBuilder
+                               .buildObject(Issuer.DEFAULT_ELEMENT_NAME);
+               i.setValue(issuer);
+               assertion.setIssuer(i);
+
+               // if audiences were specified, set an AudienceRestriction condition
+               if (audiences != null && audiences.length > 0) {
+
+                       Conditions conditions = assertion.getConditions();
+                       List<AudienceRestriction> audienceRestrictionConditions = conditions
+                                       .getAudienceRestrictions();
+
+                       for (String audienceURI : audiences) {
+
+                               Audience audience = (Audience) audienceBuilder
+                                               .buildObject(Audience.DEFAULT_ELEMENT_NAME);
+                               audience.setAudienceURI(audienceURI);
+
+                               AudienceRestriction audienceRestriction = (AudienceRestriction) audienceRestrictionBuilder
+                                               .buildObject(AudienceRestriction.DEFAULT_ELEMENT_NAME);
+                               List<Audience> audienceList = audienceRestriction
+                                               .getAudiences();
+                               audienceList.add(audience);
+
+                               audienceRestrictionConditions.add(audienceRestriction);
+                       }
+               }
+
+               return assertion;
+       }
 }
index c7755ad..d075ead 100644 (file)
@@ -15,7 +15,6 @@
  */
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
-
 import java.io.InputStream;
 import java.io.IOException;
 import java.net.MalformedURLException;
@@ -45,11 +44,13 @@ import org.joda.time.DateTime;
 import org.opensaml.Configuration;
 import org.opensaml.DefaultBootstrap;
 import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.AudienceRestriction;
 import org.opensaml.saml2.core.AuthnContext;
 import org.opensaml.saml2.core.AuthnContextClassRef;
 import org.opensaml.saml2.core.AuthnContextDeclRef;
 import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
 import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.Conditions;
 import org.opensaml.saml2.core.GetComplete;
 import org.opensaml.saml2.core.IDPEntry;
 import org.opensaml.saml2.core.IDPList;
@@ -58,8 +59,6 @@ import org.opensaml.saml2.core.RequestedAuthnContext;
 import org.opensaml.saml2.core.Response;
 import org.opensaml.saml2.core.Scoping;
 import org.opensaml.saml2.core.Status;
-import org.opensaml.saml2.core.SamlCode;
-import org.opensaml.saml2.core.StatusMessage;
 import org.opensaml.saml2.core.Subject;
 import org.opensaml.saml2.core.SubjectConfirmation;
 import org.opensaml.saml2.metadata.AssertionConsumerService;
@@ -77,724 +76,756 @@ import org.w3c.dom.Element;
 
 import org.xml.sax.InputSource;
 
-
 /**
  * SAML 2.0 Authentication Request profile handler
  */
 public class AuthenticationRequest extends AbstractProfileHandler {
-    
-    private static final Logger log = Logger.getLogger(AuthenticationRequest.class.getName());
-    
-    /** SAML 2.0 protocol URI. */
-    public static final String SAML20_PROTOCOL_URI = "urn:oasis:names:tc:SAML:2.0:protocol";
-    
-    /** The RelyingPartyManager. */
-    protected RelyingPartyManager rpManager;
-    
-    /** Backing store for artifacts. This must be shared between ShibbolethSSO and AttributeQuery. */
-    protected ArtifactMap artifactMap;
-    
-    /** The path to the IdP's AuthenticationManager servlet */
-    protected String authnMgrURL;
-    
-    /** AuthenticationManager to be used */
-    protected AuthenticationManager authnMgr;
-    
-    /** ArtifactFactory used to make artifacts. */
-    protected SAMLArtifactFactory artifactFactory;
-    
-    /** A pool of XML parsers. */
-    protected ParserPool parserPool;
-    
-    /** Builder for Assertion elements. */
-    protected XMLObjectBuilder assertionBuilder;
-    
-    /** Builder for AuthnStatement elements. */
-    protected XMLObjectBuilder authnStatementBuilder;
-    
-    /** Builder for AuthnContext elements. */
-    protected XMLObjectBuilder authnContextBuilder;
-    
-    /** Builder for AuthnContextClassRef elements. */
-    protected XMLObjectBuilder authnContextClassRefBuilder;
-    
-    /** Builder for AuthnContextDeclRef elements. */
-    protected XMLObjectBuilder authnContextDeclRefBuilder;
-    
-    /** Builder for Response elements. */
-    protected XMLObjectBuilder responseBuilder;
-    
-    /** Builder for Issuer elements. */
-    protected XMLObjectBuilder issuerBuilder;
-    
-    /** Builder for Status elements. */
-    protected XMLObjectBuilder statusBuilder;
-    
-    /** Builder for StatusCode elements. */
-    protected XMLObjectBuilder statusCodeBuilder;
-    
-    /** Builder for StatusMessage elements. */
-    protected XMLObjectBuilder statusMessageBuilder;
-    
-    
-    /**
-     * Constructor.
-     */
-    public AuthenticationRequest() {
-       
-       parserPool = new ParserPool();
-       artifactFactory = new SAMLArtifactFactory();
-       
-       assertionBuilder            = getBuilderFactory().getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
-       authnStatementBuilder       = getBuilderFactory().getBuilder(AuthnStatment.DEFULT_ELEMENT_NAME);
-       authnContextBuilder         = getBuilderFactory().getBuilder(AuthnContext.DEFAULT_ELEMENT_NAME);
-       authnContextClassRefBuilder = getBuilderFactory().getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
-       authnContextDeclRefBuilder  = getBuilderFactory().getBuilder(AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
-       responseBuilder             = getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
-       issuerBuilder               = getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
-       statusBuilder               = getBuilderFactory().getBuilder(Status.DEFAILT_ELEMENT_NAME);
-       statusCodeBuilder           = getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
-       statusMessageBuilder        = getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
-    }
-    
-    
-    /**
-     * Set the Authentication Mananger.
-     *
-     * @param authnManager The IdP's AuthenticationManager.
-     */
-    public void setAuthenticationManager(AuthenticationManager authnManager) {
-       this.authnMgr = authnMgr;
-    }
-    
-    
-    /**
-     * Set the RelyingPartyManager.
-     *
-     * @param rpManager The IdP's RelyingParyManager.
-     */
-    public void setRelyingPartyManager(RelyingPartyManager rpManager) {
-       this.rpManager = rpManager;
-    }
-    
-    
-    /**
-     * Set the ArtifactMap.
-     *
-     * @param artifactMap The IdP's ArtifactMap.
-     */
-    public void setArtifactMap(ArtifactMap artifactMap) {
-       this.artifactMap = artifactMap;
-    }
-    
-    
-    /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
-       
-       // Only http servlets are supported for now.
-       if (!(request instanceof HttpServletRequest)) {
-           log.error("Received a non-HTTP request from " + request.getRemoteHost());
-           throw new ServletException("Received a non-HTTP request");
-       }
-       
-       HttpServletRequest httpReq = (HttpServletRequest)request;
-       HttpServletResponse httpResp = (HttpServletResponse)response;
-       HttpSession httpSession = httpReq.getSession();
-
-       AuthnRequest authnRequest;
-       try {
-           authnRequest = decodeMessage(request); // this will need to change to accomodate the factory
-       } catch (BindingException ex) {
-           log.error("Unable to decode SAML 2 authentication request", ex);
-           throw new ServletException("Error decoding SAML 2 authentication request", ex);
-       }
-       
-       Issuer issuer = authnRequest.getIssuer();
-       String providerId = authnRequest.getIssuer().getSPProvidedID();
-       RelyingPartyConfiguration relyingParty = rpManager.getRelyingPartyConfiguration(providerId);
-       SSOConfiguration ssoConfig = relyingParty.getProfileConfigurations().get(SSOConfiguration.PROFILE_ID);
-       SPSSODescriptor spDescriptor;
-       
-       // if the user hasn't been authenticated, validate the AuthnRequest and
-       // redirect to AuthenticationManager to authenticate them.
-       // otherwise, generate an AuthenticationStatement.
-       if (!hasUserAuthenticated()) {
-                   
-           StatusCode failureStatus;
-           
-           if (!verifyAuthnRequest(authnRequest, failureStatus)) {
-               Response response = buildResponse(authnRequest.getID(), 
-                   relyingParty.getProviderID(), failureStatus);
-               // XXX: TODO: send response;
-           }
-           authenticateUser(authnRequest, httpSession, httpReq, httpResp);
-       }
-       
-       
-       Saml2LoginContext loginCtx = getLoginContext(httpSession);
-       if (!loginCtx.getAuthenticationOK()) {
-           // if authentication failed, send the appropriate SAML error message.
-           String failureMessage = loginCtx.getAuthenticationFailureMessage();
-           Status failureStatus = getStatus(StatusCode.RESPONDER_URI, StatusCode.AUTHN_FAILED_URI, failureMessage);
-           Response response = buildResponse(authnRequest.getID(), relyingParty.getProviderID(), failureStatus);
-           // XXX: TODO: send the response.
-           
-           return true;
-       }
-       
-       // the user successfully authenticated. built an authentication assertion.
-       Response response = buildResponse(authnRequest.getID(), relyingParty.getProviderID(),
-           buildStatus(StatusCode.SUCCESS_URI, null, null));
-
-       // build assertion
-       // add assertion to response
-       // send response
-       
-       return true;
-    }
-    
-    
-    /**
-     * 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>
-     */
-    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);
-    }
-    
-    
-    /**
-     * 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.
-     *
-     * @return A LoginContext for the authenticated user.
-     *
-     * @throws SerlvetException on error.
-     */
-    protected void authenticateUser(final AuthnRequest authnRequest, final HttpSession httpSession,
-           final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
-       
-       // Forward the request to the AuthenticationManager.
-       // When the AuthenticationManager is done it will
-       // forward the request back to this servlet.
-       
-       loginCtx = new Saml2LoginContext(authnRequest);
-       loginCtx.setProfileHandlerURL(httpReq.getPathInfo());
-       httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginCtx);
-       try {
-           RequestDispatcher dispatcher = request.getRequestDispatcher(authnMgrURL);
-           dispatcher.forward(request, response);
-       } catch (IOException ex) {
-           log.error("Error forwarding SAML 2 AuthnRequest " + authnRequest.getID() + " to AuthenticationManager", ex);
-           throw new ServletException("Error forwarding SAML 2 AuthnRequest " 
-               + authnRequest.getID() + " to AuthenticationManager", ex);
-       }
-    }
-    
-    
-    /**
-     * Build an AuthenticationStatement and add it to the Response.
-     *
-     */
-    protected void setAuthenticationStatement(Response response, final LoginContext loginCtx,
-       final AuthnRequest authnRequest, final SSOConfig ssoConfig, String issuer, String audience) throws ServletException {
-       
-       if (ssoConfig.getEncryptAssertion()) {
-           // encrypt the assertion
-       }
-       
-       Assertion assertion = (Assertion)assertionBuilder.buildObject(Assertion.DEFAULT_ELEMENT_NAME);
-       assertion.setID(getIdGenerator().generateIdentifier());
-       assertion.setVersion(SAML_VERSION);
-       assertion.setIssueInstant(new DateTime());
-       assertion.setConditions(authnRequest.getConditions());
-       assertion.setSubject(authnRequest.getSubject());
-       
-       
-       Issuer i = (Issuer)issuerBuilder.buildObject(Issuer.DEFAULT_ELEMENT_NAME);
-       i.setValue(issuer);
-       assertion.setIssuer(i);
-       
-       // Build the AuthnCtx. We need to determine if the user was authenticated
-       // with an AuthnContextClassRef or a AuthnContextDeclRef
-       AuthnContext authnCtx = buildAuthnCtx(authnRequest, loginCtx.getAuthenticationMethod());
-       if (authnCtx == null) {
-           log.error("Error respond to SAML 2 AuthnRequest " + authnRequest.getID()
-               + " : Unable to determine authentication method");
-       }
-       
-       
-       AuthnStatement stmt = (AuthnStatement)authnStatementBuilder.buildObject(AuthnStatment.DEFAULT_ELEMENT_NAME);
-       stmt.setAuthnInstant(loginCtx.getAuthenticationInstant());
-       stmt.setAuthnContext(authnCtx);
-       
-       // add the AuthnStatement to the Assertion
-       List<AuthnStatement> authnStatements = assertion.getAuthnStatements();
-       authnStatements.add(stmt);
-       
-       
-       // add the Assertion to the Response
-       List<Assertion> assertions = response.getAssertions();
-       assertions.add(assertion);
-    }
-    
-    
-    /**
-     * 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 authnMethod The authentication method that was used.
-     *
-     * @return An AuthnCtx object on success or <code>null</code> on failure.
-     */
-    protected AuthnContext buildAuthnCtx(final RequestedAuthnContext requestedAuthnCtx, String authnMethod) {
-       
-       // this method assumes that only one URI will match.
-       
-       AuthnContext authnCtx = (AuthnCtx)authnContextBuilder.buildObject(AuthnContext.DEFAULT_ELEMENT_NAME);
-       String authnMethod = loginCtx.getAuthenticationMethod();
-       
-       List<AuthnContextClassRef> authnClasses = ctx.getAuthnContextClassRefs();
-        List<AuthnContextDeclRef> authnDeclRefs = ctx.getAuthnContextDeclRefs();
-    
-        if (authnClasses != null) {
-            for (AuthnContextClassRef classRef : authnClasses) {
-                if (classRef != null) {
-                    String s = classRef.getAuthnContextClassRef();
-                    if (s != null && authnMethod.equals(s)) {
-                        AuthnContextClassRef classRef
-                           = (AuthnContextClassRef)authnContextClassRefBuilder.buildObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
-                       authnCtx.setAuthnContextClassRef(classRef);
-                       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 declRef
-                          = (AuthnContextDeclRef)authnContextDeclRefBuilder.buildObject(AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
-                       authnCtx.setAuthnContextDeclRef(declRef);
-                       return authnCtx;
-                   }
-                }
-            }
-        }
-       
-       // no matches were found.
-       return null;
-    }
-    
-    
-    /**
-     * Get the User's LoginContext.
-     *
-     * @param httpSession The user's HttpSession.
-     *
-     * @return The user's LoginContext.
-     *
-     * @throws ServletException On error.
-     */
-    protected LoginContext getLoginContext(final HttpSession httpSession) throws ServletException {
-       
-       Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-       if (o == null) {
-           log.error("User's session does not contain a LoginContext object.");
-           throw new ServletException("User's session does not contain a LoginContext object.");
-       }
-       
-       if (! (o instanceof LoginContext)) {
-           log.error("Invalid login context object -- object is not an instance of LoginContext.");
-           throw new ServletException("Invalid login context object.");
-       }
-       
-       return (LoginContext)o;;
-    }
-    
-    
-    /**
-     * Verify the AuthnRequest is well-formed.
-     *
-     * On error, this method returns <code>false</code> and sets failureStatus.
-     *
-     * @param authnRequest The user's SAML 2 AuthnRequest.
-     * @param failureStatus On failure, this will be populated with appropriate status.
-     * 
-     * @return <code>true</code> if the message is well-formed. 
-     */
-    protected boolean verifyAuthnRequest(final AuthnRequest authnRequest, Status failureStatus) {
-       
-       // The Web Browser SSO profile requires that the Issuer element is present.
-       Issuer issuer = authnRequest.getIssuer();
-       if (issuer == null) {
-           log.error("Malformed SAML 2 AuthnReq - missing Issuer element.");
-           failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
-               "SAML 2 AuthnRequest " + authnRequest.getID() + " is malformed: It lacks an Issuer.");
-           return false;
+
+       private static final Logger log = Logger
+                       .getLogger(AuthenticationRequest.class.getName());
+
+       /** SAML 2.0 protocol URI. */
+       public static final String SAML20_PROTOCOL_URI = "urn:oasis:names:tc:SAML:2.0:protocol";
+
+       /** The RelyingPartyManager. */
+       protected RelyingPartyManager rpManager;
+
+       /**
+        * Backing store for artifacts. This must be shared between ShibbolethSSO
+        * and AttributeQuery.
+        */
+       protected ArtifactMap artifactMap;
+
+       /** The path to the IdP's AuthenticationManager servlet */
+       protected String authnMgrURL;
+
+       /** AuthenticationManager to be used */
+       protected AuthenticationManager authnMgr;
+
+       /** ArtifactFactory used to make artifacts. */
+       protected SAMLArtifactFactory artifactFactory;
+
+       /** A pool of XML parsers. */
+       protected ParserPool parserPool;
+
+       /** Builder for Assertion elements. */
+       protected XMLObjectBuilder assertionBuilder;
+
+       /** Builder for AuthnStatement elements. */
+       protected XMLObjectBuilder authnStatementBuilder;
+
+       /** Builder for AuthnContext elements. */
+       protected XMLObjectBuilder authnContextBuilder;
+
+       /** Builder for AuthnContextClassRef elements. */
+       protected XMLObjectBuilder authnContextClassRefBuilder;
+
+       /** Builder for AuthnContextDeclRef elements. */
+       protected XMLObjectBuilder authnContextDeclRefBuilder;
+
+       /** Builder for AudienceRestriction conditions. */
+       protected XMLObjectBuilder audienceRestrictionBuilder;
+
+       /** Builder for Audience elemenets. */
+       protected XMLObjectBuilder audienceBuilder;
+
+       /**
+        * Constructor.
+        */
+       public AuthenticationRequest() {
+
+               parserPool = new ParserPool();
+               artifactFactory = new SAMLArtifactFactory();
+
+               assertionBuilder = getBuilderFactory().getBuilder(
+                               Assertion.DEFAULT_ELEMENT_NAME);
+               authnStatementBuilder = getBuilderFactory().getBuilder(
+                               AuthnStatment.DEFULT_ELEMENT_NAME);
+               authnContextBuilder = getBuilderFactory().getBuilder(
+                               AuthnContext.DEFAULT_ELEMENT_NAME);
+               authnContextClassRefBuilder = getBuilderFactory().getBuilder(
+                               AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+               authnContextDeclRefBuilder = getBuilderFactory().getBuilder(
+                               AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
+               audienceRestrictionBuilder = getBuilderFactory().getBuilder(
+                               AudienceRestriction.DEFAULT_ELEMENT_NAME);
+               audienceBuilder = getBuilderFactory().getBuilder(
+                               Audience.DEFAULT_ELEMENT_NAME);
        }
-       
-       // Check if we are in scope to handle this AuthnRequest
-       // XXX: confirm that SPProviderID is the field we want in the issuer
-       if (!checkScope(authnRequest, issuer.getSPProvidedID(), failureStatus)) {
-           return false;
+
+       /**
+        * Set the Authentication Mananger.
+        * 
+        * @param authnManager
+        *            The IdP's AuthenticationManager.
+        */
+       public void setAuthenticationManager(AuthenticationManager authnManager) {
+               this.authnMgr = authnMgr;
        }
-       
-       // XXX: run signature checks on authnRequest
-       
-       // verify that the AssertionConsumerService url is valid.
-       AssertionConsumerService acsEndpoint = getAndVerifyACSEndpoint(authnRequest,
-           relyingParty.getRelyingPartyID(), rpManager.getMetadataProvider(), failureStatus);
-       if (acsEndpoint == null) {
-           return false;
+
+       /**
+        * Set the RelyingPartyManager.
+        * 
+        * @param rpManager
+        *            The IdP's RelyingParyManager.
+        */
+       public void setRelyingPartyManager(RelyingPartyManager rpManager) {
+               this.rpManager = rpManager;
        }
-       
-       Subject subject = getAndVerifySubject(authnRequest, failureStatus);
-       if (subject == null) {
-           return false;
+
+       /**
+        * Set the ArtifactMap.
+        * 
+        * @param artifactMap
+        *            The IdP's ArtifactMap.
+        */
+       public void setArtifactMap(ArtifactMap artifactMap) {
+               this.artifactMap = artifactMap;
        }
-       
-       // check for nameID constraints.
-    }
-    
-    
-    /**
-     * Get and verify the Subject element.
-     *
-     * On error, this method will return <code>null</code> and set failureStatus.
-     *
-     * @param authnRequest The SAML 2 AuthnRequest.
-     * @param failureStatus On failure, this will be populated with appropriate status.
-     *
-     * @return A Subject element, if one was present, otherwise <code>null</code>
-     */
-    protected Subject getAndVerifySubject(final AuthnRequest authnRequest, Status failureStatus) {
-       
-       Subject subject = authnRequest.getSubject();
-       
-       if (subject == null) {
-           failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
-                   "SAML 2 AuthnRequest " + authnRequest.getID() + " is malformed: It does not contain a Subject.");
-           return null;
+
+       /** {@inheritDoc} */
+       public boolean processRequest(ServletRequest request,
+                       ServletResponse response) throws ServletException {
+
+               // Only http servlets are supported for now.
+               if (!(request instanceof HttpServletRequest)) {
+                       log.error("Received a non-HTTP request from "
+                                       + request.getRemoteHost());
+                       throw new ServletException("Received a non-HTTP request");
+               }
+
+               HttpServletRequest httpReq = (HttpServletRequest) request;
+               HttpServletResponse httpResp = (HttpServletResponse) response;
+               HttpSession httpSession = httpReq.getSession();
+
+               AuthnRequest authnRequest;
+               try {
+                       authnRequest = decodeMessage(request); // this will need to change
+                       // to accomodate the factory
+               } catch (BindingException ex) {
+                       log.error("Unable to decode SAML 2 authentication request", ex);
+                       throw new ServletException(
+                                       "Error decoding SAML 2 authentication request", ex);
+               }
+
+               Issuer issuer = authnRequest.getIssuer();
+               String providerId = authnRequest.getIssuer().getSPProvidedID();
+               RelyingPartyConfiguration relyingParty = rpManager
+                               .getRelyingPartyConfiguration(providerId);
+               SSOConfiguration ssoConfig = relyingParty.getProfileConfigurations()
+                               .get(SSOConfiguration.PROFILE_ID);
+               SPSSODescriptor spDescriptor;
+
+               try {
+
+                       // If the user hasn't been authenticated, validate the AuthnRequest
+                       // and
+                       // redirect to AuthenticationManager to authenticate them.
+                       // Otherwise, the user has been authenticated, so generate an
+                       // AuthenticationStatement.
+                       if (!hasUserAuthenticated()) {
+                               verifyAuthnRequest(authnRequest);
+                               authenticateUser(authnRequest, httpSession, httpReq, httpResp);
+                       }
+
+                       // the user has been authenticated.
+                       // check if the authentication was successful.
+
+                       Saml2LoginContext loginCtx = getLoginContext(httpSession);
+                       if (!loginCtx.getAuthenticationOK()) {
+                               // if authentication failed, send the appropriate SAML error
+                               // message.
+                               String failureMessage = loginCtx
+                                               .getAuthenticationFailureMessage();
+                               Status failureStatus = getStatus(StatusCode.RESPONDER_URI,
+                                               StatusCode.AUTHN_FAILED_URI, failureMessage);
+                               Response response = buildResponse(authnRequest.getID(),
+                                               relyingParty.getProviderID(), failureStatus);
+
+                               // XXX: TODO: send the response.
+
+                               return true;
+                       }
+
+                       // the user successfully authenticated. build an authentication
+                       // assertion.
+                       Response response = buildResponse(authnRequest.getID(),
+                                       relyingParty.getProviderID(), buildStatus(
+                                                       StatusCode.SUCCESS_URI, null, null));
+
+                       // XXX: don't blindly copy conditions.
+                       Assertion assertion = buildAssertion(authnRequest.getSubject(),
+                                       authnRequest.getConditions(), new String[] { relyingParty
+                                                       .getRelyingPartyID() });
+                       setAuthenticationStatement(assertion, loginCtx, authnRequest);
+
+                       response.getAssertions().add(assertion);
+
+                       // XXX: send the assertion
+
+               } catch (AuthenticationRequestException ex) {
+
+                       StatusCode errorStatus = ex.getStatusCode();
+                       if (errorStatus == null) {
+                               // if no explicit status code was set, assume the error was in
+                               // the message.
+                               errorStatus = buildStatus(StatusCode.REQUESTER_URI, null, null);
+                               Response response = buildResponse(authnRequest.getID(),
+                                               relyingParty.getProviderID(), failureStatus);
+                               // XXX: TODO: send the response.
+                       }
+
+               }
+
+               // build assertion
+               // add assertion to response
+               // send response
+
+               return true;
        }
-       
-       // The Web Browser SSO profile disallows SubjectConfirmation methods
-       // in the requested subject.
-       List<SubjectConfirmation> confMethods = subject.getSubjectConfirmations();
-       if (confMethods != null || confMethods.length > 0) {
-           log.error("SAML 2 AuthnRequest " + authnRequest.getID()
-               + " is malformed: It contains SubjectConfirmation elements.");
-           failureStauts = buildStatus(StatusCode.REQUESTER_URI, null,
-               "SAML 2 AuthnRequest " + authnRequest.getID() + " is malformed: It contains SubjectConfirmation elements.");
-           return null;
+
+       /**
+        * 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>
+        */
+       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);
        }
-       
-       return subject;
-    }
-    
-    
-    /**
-     * Return the endpoint URL and protocol binding to use for the AuthnRequest.
-     *
-     * On error, this method will set failureStatus to point 
-     * to a failure status object and return <code>null</code>.
-     *
-     * @param authnRequest The SAML 2 AuthnRequest.
-     * @param providerId The SP's providerId.
-     * @param metadata The appropriate Metadata.
-     * @param failureStatus A failure status element. Will be populated on error.
-     *
-     * @return The AssertionConsumerService for the endpoint, or <code>null</code> on error.
-     *
-     * @throws ServletException On error.
-     */
-    protected AssertionConsumerService getAndVerifyACSEndpoint(final AuthnRequest authnRequest,
-           String providerId, final MetadataProvider metadata, Status failureStatus) {
-       
-       // 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");
-           failureStatus = buildStatus(StatusCode.REQUESTER_URI, null, "SAML 2 AuthnRequest " + authnRequest.getID()
-               + " is malformed: It contains both an AssertionConsumerServiceIndex and an AssertionConsumerServiceURL");
-           return null;
+
+       /**
+        * 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.
+        * 
+        * @return A LoginContext for the authenticated user.
+        * 
+        * @throws SerlvetException
+        *             on error.
+        */
+       protected void authenticateUser(final AuthnRequest authnRequest,
+                       final HttpSession httpSession, final HttpServletRequest request,
+                       final HttpServletResponse response) throws ServletException {
+
+               // Forward the request to the AuthenticationManager.
+               // When the AuthenticationManager is done it will
+               // forward the request back to this servlet.
+
+               loginCtx = new Saml2LoginContext(authnRequest);
+               loginCtx.setProfileHandlerURL(httpReq.getPathInfo());
+               httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginCtx);
+               try {
+                       RequestDispatcher dispatcher = request
+                                       .getRequestDispatcher(authnMgrURL);
+                       dispatcher.forward(request, response);
+               } catch (IOException ex) {
+                       log.error("Error forwarding SAML 2 AuthnRequest "
+                                       + authnRequest.getID() + " to AuthenticationManager", ex);
+                       throw new ServletException("Error forwarding SAML 2 AuthnRequest "
+                                       + authnRequest.getID() + " to AuthenticationManager", ex);
+               }
        }
-       
-       SPSSODescriptor spDescriptor;
-       List<AssertionConsumerService> acsList;
-       try {
-           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);
-           return null;
+
+       /**
+        * Build an AuthnStatement and add it to a Response.
+        * 
+        * @param response
+        *            The Response to which the AuthnStatement will be added.
+        * @param loginCtx
+        *            The LoginContext of the sucessfully authenticated user.
+        * @param authnRequest
+        *            The AuthnRequest that prompted this message.
+        * @param ssoConfig
+        *            The SSOConfiguration for the RP to which we are addressing
+        *            this message.
+        * @param issuer
+        *            The IdP's identifier.
+        * @param audiences
+        *            An array of URIs restricting the audience of this assertion.
+        */
+       protected void setAuthenticationStatement(Assertion assertion,
+                       final LoginContext loginCtx, final AuthnRequest authnRequest)
+                       throws ServletException {
+
+               // Build the AuthnCtx. We need to determine if the user was
+               // authenticated
+               // with an AuthnContextClassRef or a AuthnContextDeclRef
+               AuthnContext authnCtx = buildAuthnCtx(authnRequest, loginCtx
+                               .getAuthenticationMethod());
+               if (authnCtx == null) {
+                       log.error("Error respond to SAML 2 AuthnRequest "
+                                       + authnRequest.getID()
+                                       + " : Unable to determine authentication method");
+               }
+
+               AuthnStatement stmt = (AuthnStatement) authnStatementBuilder
+                               .buildObject(AuthnStatment.DEFAULT_ELEMENT_NAME);
+               stmt.setAuthnInstant(loginCtx.getAuthenticationInstant());
+               stmt.setAuthnContext(authnCtx);
+
+               // add the AuthnStatement to the Assertion
+               List<AuthnStatement> authnStatements = assertion.getAuthnStatements();
+               authnStatements.add(stmt);
        }
-       
-       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.length) {
-               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 " + authnRequest.getID());
-               
+
+       /**
+        * 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 authnMethod
+        *            The authentication method that was used.
+        * 
+        * @return An AuthnCtx object on success or <code>null</code> on failure.
+        */
+       protected AuthnContext buildAuthnCtx(
+                       final RequestedAuthnContext requestedAuthnCtx, String authnMethod) {
+
+               // this method assumes that only one URI will match.
+
+               AuthnContext authnCtx = (AuthnCtx) authnContextBuilder
+                               .buildObject(AuthnContext.DEFAULT_ELEMENT_NAME);
+               String authnMethod = loginCtx.getAuthenticationMethod();
+
+               List<AuthnContextClassRef> authnClasses = ctx
+                               .getAuthnContextClassRefs();
+               List<AuthnContextDeclRef> authnDeclRefs = ctx.getAuthnContextDeclRefs();
+
+               if (authnClasses != null) {
+                       for (AuthnContextClassRef classRef : authnClasses) {
+                               if (classRef != null) {
+                                       String s = classRef.getAuthnContextClassRef();
+                                       if (s != null && authnMethod.equals(s)) {
+                                               AuthnContextClassRef classRef = (AuthnContextClassRef) authnContextClassRefBuilder
+                                                               .buildObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+                                               authnCtx.setAuthnContextClassRef(classRef);
+                                               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 declRef = (AuthnContextDeclRef) authnContextDeclRefBuilder
+                                                               .buildObject(AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
+                                               authnCtx.setAuthnContextDeclRef(declRef);
+                                               return authnCtx;
+                                       }
+                               }
+                       }
+               }
+
+               // no matches were found.
                return null;
-           }
-           
-           return acsList.get(i);
        }
-       
-       // if the ACS endpoint is specified, validate it against the metadata
-       String protocolBinding = authnRequest.getProtocolBinding();
-       for (AssertionConumerService acs : acsList) {
-           if (acsURL.equals(acs.getLocation())) {
-               if (protocolBinding != null) {
-                   if (protocolBinding.equals(acs.getBinding())) {
-                       return acs;
-                   }
+
+       /**
+        * Get the User's LoginContext.
+        * 
+        * @param httpSession
+        *            The user's HttpSession.
+        * 
+        * @return The user's LoginContext.
+        * 
+        * @throws ServletException
+        *             On error.
+        */
+       protected LoginContext getLoginContext(final HttpSession httpSession)
+                       throws ServletException {
+
+               Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+               if (o == null) {
+                       log.error("User's session does not contain a LoginContext object.");
+                       throw new ServletException(
+                                       "User's session does not contain a LoginContext object.");
                }
-           }
-       }
-       
-       log.error("Error processing SAML 2 AuthnRequest message " + authnRequest.getID()
-           + ": Unable to validate AssertionConsumerServiceURL against metadata: "
-           + acsURL + " for binding " + protocolBinding);
-       
-       failureStatus = buildStatus(statusCodeBuilder.REQUESTER_URI, null,
-               "Unable to validate AssertionConsumerService against metadata");
-
-       return null;
-    }
-    
-    
-    /**
-     * 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>.
-     *
-     * If this method returns <code>false</code>, the caller 
-     * should check if <code>failureStatus</code> has been set.
-     *
-     * @param authnRequest The {@link AuthnRequest} element to check.
-     * @param providerId The IdP's ProviderID
-     * @param failureStatus Set to a failure code on error.
-     *
-     * @return <code>true</code>if idp is in the IDPList, otherwise <code>false</code>
-     */
-    protected boolean checkScope(final AuthnRequest authnRequest, String providerId, Status failureStatus) {
-       
-       List<String> idpEntries = new LinkedList<String>();
-               
-       Scoping scoping = authnRequest.getScoping();
-       if (scoping == null) {
-           return true;
-       }
-       
-       // process all of the explicitly listed idp provider ids
-       IDPList idpList = scoping.getIDPList();
-       if (idpList == null) {
-           return true;
-       }
-       
-       List<IDPEntry> explicitIDPEntries = idpList.getIDPEntrys();
-       if (explicitIDPEntries != null) {
-           for (IDPEntry entry : explicitIDPEntries) {
-               String s = entry.getProviderID();
-               if (s != null) {
-                   idpEntries.add(s);
+
+               if (!(o instanceof LoginContext)) {
+                       log
+                                       .error("Invalid login context object -- object is not an instance of LoginContext.");
+                       throw new ServletException("Invalid login context object.");
                }
-           }
+
+               return (LoginContext) o;
+               ;
        }
-       
-       
-       // If the IDPList is incomplete, retrieve the complete list
-       // and add the entries to idpEntries.
-       GetComplete getComplete = idpList.getGetComplete();
-       IDPList referencedIdPs = getCompleteIDPList(getComplete);
-       if (referencedIdPs != null) {
-           List<IDPEntry> referencedIDPEntries = referencedIdPs.getIDPEntrys();
-           if (referencedIDPEntries != null) {
-               for (IDPEntry entry : referencedIDPEntries) {
-                   String s = entry.getProviderID();
-                   if (s != null) {
-                       idpEntries.add(s);
-                   }
+
+       /**
+        * Verify the AuthnRequest is well-formed.
+        * 
+        * @param authnRequest
+        *            The user's SAML 2 AuthnRequest.
+        * 
+        * @throws AuthenticationRequestException
+        *             on error.
+        */
+       protected void verifyAuthnRequest(final AuthnRequest authnRequest)
+                       throws AuthenticationRequestException {
+
+               Status failureStatus;
+
+               // The Web Browser SSO profile requires that the Issuer element is
+               // present.
+               Issuer issuer = authnRequest.getIssuer();
+               if (issuer == null) {
+                       log.error("Malformed SAML 2 AuthnReq - missing Issuer element.");
+                       failureStatus = buildStatus(StatusCode.REQUESTER_URI, null,
+                                       "SAML 2 AuthnRequest " + authnRequest.getID()
+                                                       + " is malformed: It lacks an Issuer.");
+                       throw new AuthenticationRequestException(
+                                       "AuthnRequest lacks an Issuer", failureStatus);
                }
-           }
+
+               // Check if we are in scope to handle this AuthnRequest
+               // XXX: confirm that SPProviderID is the field we want in the issuer
+               if (!checkScope(authnRequest, issuer.getSPProvidedID())) {
+                       return false;
+               }
+
+               // XXX: run signature checks on authnRequest
+
+               // verify that the AssertionConsumerService url is valid.
+               AssertionConsumerService acsEndpoint = getAndVerifyACSEndpoint(
+                               authnRequest, relyingParty.getRelyingPartyID(), rpManager
+                                               .getMetadataProvider());
+
+               Subject subject = getAndVerifySubject(authnRequest, failureStatus);
+
+               // check for nameID constraints.
        }
-       
-       
-       // iterate over all the IDPEntries we've gathered,
-       // and check if we're in scope.
-       for (String requestProviderId : idpEntries) {
-           if (providerId.equals(requestProviderId)) {
-               found = true;
-               log.debug("Found Scoping match for IdP: (" + providerId + ")");
-               return true;
-           }
+
+       /**
+        * Get and verify the Subject element.
+        * 
+        * @param authnRequest
+        *            The SAML 2 AuthnRequest.
+        * 
+        * @return A Subject element.
+        * 
+        * @throws AuthenticationRequestException
+        *             on error.
+        */
+       protected Subject getAndVerifySubject(final AuthnRequest authnRequest)
+                       throws AuthenticationRequestException {
+
+               Status failureStatus;
+
+               Subject subject = authnRequest.getSubject();
+
+               if (subject == null) {
+                       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);
+               }
+
+               // The Web Browser SSO profile disallows SubjectConfirmation
+               // methods in the requested subject.
+               List<SubjectConfirmation> confMethods = subject
+                               .getSubjectConfirmations();
+               if (confMethods != null || confMethods.length > 0) {
+                       log
+                                       .error("SAML 2 AuthnRequest "
+                                                       + authnRequest.getID()
+                                                       + " is malformed: It contains SubjectConfirmation elements.");
+                       failureStauts = buildStatus(
+                                       StatusCode.REQUESTER_URI,
+                                       null,
+                                       "SAML 2 AuthnRequest "
+                                                       + authnRequest.getID()
+                                                       + " is malformed: It contains SubjectConfirmation elements.");
+                       throw new AuthenticationRequestException(
+                                       "AuthnRequest contains SubjectConfirmation elements",
+                                       failureStatus);
+               }
+
+               return subject;
        }
-       
-       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);
-       return false;
-    }
-    
-    
-    /**
-     * Retrieve an incomplete IDPlist.
-     *
-     * This only handles URL-based <GetComplete/> references.
-     *
-     * @param getComplete The (possibly <code>null</code>) &lt;GetComplete/&gt; 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;
+
+       /**
+        * Return the endpoint URL and protocol binding to use for the AuthnRequest.
+        * 
+        * @param authnRequest
+        *            The SAML 2 AuthnRequest.
+        * @param providerId
+        *            The SP's providerId.
+        * @param metadata
+        *            The appropriate Metadata.
+        * 
+        * @return The AssertionConsumerService for the endpoint, or
+        *         <code>null</code> on error.
+        * 
+        * @throws AuthenticationRequestException
+        *             On error.
+        */
+       protected AssertionConsumerService getAndVerifyACSEndpoint(
+                       final AuthnRequest authnRequest, String providerId,
+                       final MetadataProvider metadata)
+                       throws AuthenticationRequestException {
+
+               Status failureStatus;
+
+               // 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");
+                       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);
+               }
+
+               SPSSODescriptor spDescriptor;
+               try {
+                       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);
+               }
+
+               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.length) {
+                               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 "
+                                                               + authnRequest.getID());
+
+                               throw new AuthenticationRequestException(
+                                               "Illegal AssertionConsumerIndex in AuthnRequest",
+                                               failureStatus);
+                       }
+
+                       return acsList.get(i);
+               }
+
+               // if the ACS endpoint is specified, validate it against the metadata
+               String protocolBinding = authnRequest.getProtocolBinding();
+               for (AssertionConumerService acs : acsList) {
+                       if (acsURL.equals(acs.getLocation())) {
+                               if (protocolBinding != null) {
+                                       if (protocolBinding.equals(acs.getBinding())) {
+                                               return acs;
+                                       }
+                               }
+                       }
+               }
+
+               log
+                               .error("Error processing SAML 2 AuthnRequest message "
+                                               + authnRequest.getID()
+                                               + ": Unable to validate AssertionConsumerServiceURL against metadata: "
+                                               + acsURL + " for binding " + protocolBinding);
+
+               failureStatus = buildStatus(statusCodeBuilder.REQUESTER_URI, null,
+                               "Unable to validate AssertionConsumerService against metadata.");
+
+               throw new AuthenticationRequestException(
+                               "Unabel to validate AssertionConsumerService against Metadata",
+                               failureStatus);
        }
-       
-       String uri = getComplete.getGetComplete();
-       if (uri != null) {
-           return null;
+
+       /**
+        * 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 {
+
+               Status failureStatus;
+
+               List<String> idpEntries = new LinkedList<String>();
+
+               Scoping scoping = authnRequest.getScoping();
+               if (scoping == null) {
+                       return true;
+               }
+
+               // 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) {
+                               String s = entry.getProviderID();
+                               if (s != null) {
+                                       idpEntries.add(s);
+                               }
+                       }
+               }
+
+               // If the IDPList is incomplete, retrieve the complete list
+               // and add the entries to idpEntries.
+               GetComplete getComplete = idpList.getGetComplete();
+               IDPList referencedIdPs = getCompleteIDPList(getComplete);
+               if (referencedIdPs != null) {
+                       List<IDPEntry> referencedIDPEntries = referencedIdPs.getIDPEntrys();
+                       if (referencedIDPEntries != null) {
+                               for (IDPEntry entry : referencedIDPEntries) {
+                                       String s = entry.getProviderID();
+                                       if (s != null) {
+                                               idpEntries.add(s);
+                                       }
+                               }
+                       }
+               }
+
+               // iterate over all the IDPEntries we've gathered,
+               // and check if we're in scope.
+               for (String requestProviderId : idpEntries) {
+                       if (providerId.equals(requestProviderId)) {
+                               found = true;
+                               log.debug("Found Scoping match for IdP: (" + providerId + ")");
+                               return;
+                       }
+               }
+
+               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);
        }
-       
-       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);
-           idpList = (IDPList) unmarshaller.unmarshall(docElement);
-           
-       } catch (MalformedURLException 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);
-       } catch (ConfigurationException ex) {
-           log.error("Internal OpenSAML error while parsing GetComplete IDPList from " + uri, ex);
-       } catch (XMLParserException 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);
-       } finally {
-           
-           if (istream != null) {
+
+       /**
+        * Retrieve an incomplete IDPlist.
+        * 
+        * This only handles URL-based <GetComplete/> references.
+        * 
+        * @param getComplete
+        *            The (possibly <code>null</code>) &lt;GetComplete/&gt;
+        *            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 {
-                   istream.close();
+                       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);
+                       idpList = (IDPList) unmarshaller.unmarshall(docElement);
+
+               } catch (MalformedURLException ex) {
+                       log.error(
+                                       "Unable to retrieve GetComplete IDPList. Unsupported URI: "
+                                                       + uri, ex);
                } catch (IOException ex) {
-                   // nothing to do here.
+                       log.error("IO Error while retreieving GetComplete IDPList from "
+                                       + uri, ex);
+               } catch (ConfigurationException ex) {
+                       log.error(
+                                       "Internal OpenSAML error while parsing GetComplete IDPList from "
+                                                       + uri, ex);
+               } catch (XMLParserException 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);
+               } finally {
+
+                       if (istream != null) {
+                               try {
+                                       istream.close();
+                               } catch (IOException ex) {
+                                       // pass
+                               }
+                       }
                }
-           }
-       }
-       
-       return idpList;
-    }
-    
-    
-    /**
-     * 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 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, String issuer, final Status status) {
-       
-       Response response = (Response)responseBuilder.buildObject(Response.DEFAULT_ELEMENT_NAME);
-       
-       Issuer i = (Issuer)issuerBuilder.buildObject(Issuer.DEFAULT_ELEMENT_NAME);
-       i.setValue(issuer);
-       
-       response.setVersion(SAML_VERSION);
-       response.setId(getIdGenerator().generateIdentifier());
-       response.setInResponseto(inResponseTo);
-       response.setIssueInstance(new DateTime());
-       response.setIssuer(i);
-       response.setStatus(status);
-       
-       return response;
-    }
-    
-    
-    /**
-     * Build a status message, with an optional second-level failure message.
-     *
-     * @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
-     * @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2.
-     *                 If null, no second-level Status element will be set.
-     * @param secondLevelFailureMessage An optional second-level failure message.
-     * @return a Status object.
-     */
-    protected Status buildStatus(String topLevelCode,
-           String secondLevelCode, String secondLevelFailureMessage) {
-       
-       Status status = (Status)statusBuilder.buildObject(Status.DEFAULT_ELEMENT_NAME);
-       StatusCode statusCode = (StatusCode)statusCodeBuilder.buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
-       
-       statusCode.setValue(topLevelCode);
-       if (secondLevelCode != null) {
-           StatusCode secondLevelStatusCode = (StatusCode)statusCodeBuilder.buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
-           secondLevelStatusCode.setValue(secondLevelCode);
-           statusCode.setStatusCode(secondLevelStatusCode);
-       }
-       
-       if (secondLevelFailureMessage != null) {
-           StatusMessage msg = (StatusMessage)statusMessageBuilder.buildObject(StatusMessage.DEFAULT_ELEMENT_NAME);
-           msg.setMessage(secondLevelFailureMessage);
+
+               return idpList;
        }
-       
-       return status;
-    }
 }
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AuthenticationRequestException.java b/src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AuthenticationRequestException.java
new file mode 100644 (file)
index 0000000..d817eae
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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.StatusCode;
+
+/**
+ * Indicates an error while processing an {@link AuthenticationRequest}.
+ */
+public class AuthenticationRequestException extends java.lang.Exception {
+
+       protected StatusCode statusCode = null;
+
+       /**
+        * Get the SAML 2 StatusCode, if any, associated with this error.
+        * 
+        * @return A SAML 2 StatusCode object, or <code>null</code> if none was
+        *         set.
+        */
+       public StatusCode getStatusCode() {
+               return statusCode;
+       }
+
+       /**
+        * 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 code
+        *            A SAML 2 StatusCode indicated which error should be returned
+        *            to the requestor.
+        */
+       public AuthenticationRequestException(final String message,
+                       final StatusCode code) {
+               super(message);
+               statusCode = code;
+       }
+
+       /**
+        * 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 StatusCode indicated which error should be returned
+        *            to the requestor.
+        */
+       public AuthenticationRequestException(final Throwable cause,
+                       final StatusCode code) {
+               super(cause);
+               statusCode = code;
+       }
+
+       /**
+        * 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 StatusCode indicated which error should be returned
+        *            to the requestor.
+        */
+       public AuthenticationRequestException(final String message,
+                       final Throwable cause, final StatusCode code) {
+               super(message, cause);
+               statusCode = code;
+       }
+
+}