Modified method signatures to use ProfileRequest and ProfileResponse.
authordfisher <dfisher@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 30 Mar 2007 22:01:12 +0000 (22:01 +0000)
committerdfisher <dfisher@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 30 Mar 2007 22:01:12 +0000 (22:01 +0000)
Added ShibbolethProfileRequest and ShibbolethProfileResponse implementatations of new interfaces.
Added ProfileResponseContext for passing around all those bits of data you need when creating a SAML response.
Cleaned up saml2 attribute query.
Ran eclipse formatting on files as I went.
Stiil not clear which pieces will fall out into the AbstractProfileHandler class.

git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@2169 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileRequest.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileResponse.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ArtifactQuery.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/AttributeQuery.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSO.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AbstractProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/ArtifactResolution.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AttributeQuery.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AuthenticationRequest.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/LogoutRequest.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/ProfileResponseContext.java [new file with mode: 0644]

diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileRequest.java b/src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileRequest.java
new file mode 100644 (file)
index 0000000..4b73869
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.profile;
+
+import javax.servlet.ServletRequest;
+
+import org.opensaml.common.binding.MessageDecoder;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+
+/**
+ * Shibboleth {@link ProfileRequest}.
+ */
+public class ShibbolethProfileRequest implements ProfileRequest {
+
+    /** Request to process. */
+    private ServletRequest request;
+
+    /** For decoding requests. */
+    private MessageDecoder<ServletRequest> messageDecoder;
+
+    /**
+     * Constructor.
+     * 
+     * @param r to process
+     * @param d for decoding the servlet request
+     */
+    public ShibbolethProfileRequest(ServletRequest r, MessageDecoder<ServletRequest> d) {
+        request = r;
+        messageDecoder = d;
+    }
+
+    /** {@inheritDoc} */
+    public ServletRequest getRequest() {
+        return request;
+    }
+
+    /** {@inheritDoc} */
+    public MessageDecoder<ServletRequest> getMessageDecoder() {
+        return messageDecoder;
+    }
+}
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileResponse.java b/src/edu/internet2/middleware/shibboleth/idp/profile/ShibbolethProfileResponse.java
new file mode 100644 (file)
index 0000000..fb52252
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.profile;
+
+import javax.servlet.ServletResponse;
+
+import org.opensaml.common.binding.MessageEncoder;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+
+/**
+ * Shibboleth {@link ProfileResponse}.
+ */
+public class ShibbolethProfileResponse implements ProfileResponse {
+
+    /** Response to send back to client. */
+    private ServletResponse response;
+
+    /** For encoding responses. */
+    private MessageEncoder<ServletResponse> messageEncoder;
+
+    /**
+     * Constructor.
+     * 
+     * @param r to send back
+     * @param e for encoding the servlet response
+     */
+    public ShibbolethProfileResponse(ServletResponse r, MessageEncoder<ServletResponse> e) {
+        response = r;
+        messageEncoder = e;
+    }
+
+    /** {@inheritDoc} */
+    public ServletResponse getResponse() {
+        return response;
+    }
+
+    /** {@inheritDoc} */
+    public MessageEncoder<ServletResponse> getMessageEncoder() {
+        return messageEncoder;
+    }
+}
index c3ad48a..6b9d7df 100644 (file)
 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
 
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 
 import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 
 /**
  * SAML 1 Artifact Query profile handler.
@@ -27,7 +27,7 @@ import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
 public class ArtifactQuery implements ProfileHandler {
 
     /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
         // TODO Auto-generated method stub
         return false;
     }
index 469a8d9..89a8535 100644 (file)
 
 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
 
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 
 import org.apache.log4j.Logger;
 import org.joda.time.DateTime;
@@ -35,7 +36,7 @@ import org.opensaml.saml1.core.Subject;
 import org.opensaml.saml1.core.SubjectStatement;
 import org.opensaml.xml.encryption.EncryptionException;
 
-import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
+import edu.internet2.middleware.shibboleth.common.attribute.filtering.AttributeFilteringException;
 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
 
 /**
@@ -47,7 +48,7 @@ public class AttributeQuery extends AbstractProfileHandler {
     private static Logger log = Logger.getLogger(AttributeQuery.class);
 
     /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
         if (log.isDebugEnabled()) {
             log.debug("begin processRequest");
         }
index 7afa93d..55f10e9 100644 (file)
@@ -16,6 +16,9 @@
 
 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
 
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.security.MessageDigest;
@@ -74,936 +77,794 @@ import org.opensaml.xml.signature.Signature;
 /**
  * Shibboleth, version 1.X, single sign-on profile handler.
  * 
- * This profile implements the SSO profile from "Shibboleth Architecture
- * Protocols and Profiles" - 10 September 2005.
+ * This profile implements the SSO profile from "Shibboleth Architecture Protocols and Profiles" - 10 September 2005.
  */
 public class ShibbolethSSO extends AbstractProfileHandler {
 
-       /** log4j. */
-       private static final Logger log = Logger.getLogger(ShibbolethSSO.class);
+    /** log4j. */
+    private static final Logger log = Logger.getLogger(ShibbolethSSO.class);
+
+    /** SAML 1 bearer confirmation method URI. */
+    protected static final String BEARER_CONF_METHOD_URI = "urn:oasis:names:tc:SAML:1.0:cm:bearer";
+
+    /** SAML 1 artifact confirmation method URI */
+    protected static final String ARTIFACT_CONF_METHOD_URI = "urn:oasis:names:tc:SAML:1.0:cm:artifact";
+
+    /** SAML 1.1 SPSSO protocol URI */
+    protected static final String SAML11_PROTOCOL_URI = "urn:oasis:names:tc:SAML:1.1:protocol";
 
-       /** SAML 1 bearer confirmation method URI. */
-       protected static final String BEARER_CONF_METHOD_URI = "urn:oasis:names:tc:SAML:1.0:cm:bearer";
+    /** SAML 1 Browser/POST protocol URI. */
+    protected static final String PROFILE_BROWSER_POST_URI = "urn:oasis:names:tc:SAML:1.0:profiles:browser-post";
 
-       /** SAML 1 artifact confirmation method URI */
-       protected static final String ARTIFACT_CONF_METHOD_URI = "urn:oasis:names:tc:SAML:1.0:cm:artifact";
+    /** SAML 1 Artifact protocol URI. */
+    protected static final String PROFILE_ARTIFACT_URI = "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01";
 
-       /** SAML 1.1 SPSSO protocol URI */
-       protected static final String SAML11_PROTOCOL_URI = "urn:oasis:names:tc:SAML:1.1:protocol";
+    /** The digest algorithm for generating SP cookies. */
+    protected static final String RP_COOKIE_DIGEST_ALG = "SHA-1";
 
-       /** SAML 1 Browser/POST protocol URI. */
-       protected static final String PROFILE_BROWSER_POST_URI = "urn:oasis:names:tc:SAML:1.0:profiles:browser-post";
+    /** The RelyingPartyManager. */
+    protected RelyingPartyManager rpManager;
 
-       /** SAML 1 Artifact protocol URI. */
-       protected static final String PROFILE_ARTIFACT_URI = "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01";
+    /**
+     * Backing store for artifacts. This must be shared between ShibbolethSSO and AttributeQuery.
+     */
+    protected ArtifactMap artifactMap;
 
-       /** The digest algorithm for generating SP cookies. */
-       protected static final String RP_COOKIE_DIGEST_ALG = "SHA-1";
+    /** The path to the IdP's AuthenticationManager servlet */
+    protected String authnMgrURL;
 
-       /** The RelyingPartyManager. */
-       protected RelyingPartyManager rpManager;
+    /** The URI of the default authentication method */
+    protected String authenticationMethodURI;
 
-       /**
-        * Backing store for artifacts. This must be shared between ShibbolethSSO
-        * and AttributeQuery.
-        */
-       protected ArtifactMap artifactMap;
+    /** Builder for AuthenticationStatement objects. */
+    protected XMLObjectBuilder authnStmtBuilder;
 
-       /** The path to the IdP's AuthenticationManager servlet */
-       protected String authnMgrURL;
+    /** Builder for Subject elements. */
+    protected XMLObjectBuilder subjectbuilder;
 
-       /** The URI of the default authentication method */
-       protected String authenticationMethodURI;
+    /** Builder for SubjectConfirmation objects. */
+    protected XMLObjectBuilder subjConfBuilder;
 
-       /** Builder for AuthenticationStatement objects. */
-       protected XMLObjectBuilder authnStmtBuilder;
+    /** Builder for SubjectConfirmationMethod objects. */
+    protected XMLObjectBuilder confMethodBuilder;
 
-       /** Builder for Subject elements. */
-       protected XMLObjectBuilder subjectbuilder;
+    /** Builder for Artifacts. */
+    protected XMLObjectBuilder artifactBuilder;
 
-       /** Builder for SubjectConfirmation objects. */
-       protected XMLObjectBuilder subjConfBuilder;
+    /** Builder for NameIdentifiers. */
+    protected XMLObjectBuilder nameIdentifierBuilder;
 
-       /** Builder for SubjectConfirmationMethod objects. */
-       protected XMLObjectBuilder confMethodBuilder;
-
-       /** Builder for Artifacts. */
-       protected XMLObjectBuilder artifactBuilder;
-
-       /** Builder for NameIdentifiers. */
-       protected XMLObjectBuilder nameIdentifierBuilder;
-
-       /** Builder for Audience elements. */
-       protected XMLObjectBuilder audienceBuilder;
-
-       /** Builder for AudienceRestrictionCondition elements. */
-       protected XMLObjectBuilder audienceRestrictionBuilder;
-
-       /** Builder for Assertions. */
-       protected XMLObjectBuilder assertionBuilder;
-
-       /** Builder for Status objects. */
-       protected XMLObjectBuilder statusBuilder;
-
-       /** Builder for StatusCode objects. */
-       protected XMLObjectBuilder statusCodeBuilder;
-
-       /** Builder for StatusMessage objects. */
-       protected XMLObjectBuilder statusMessageBuilder;
-
-       /** Builder for Response objects. */
-       protected XMLObjectbuilder responseBuilder;
-
-       /** Block stale requests. */
-       protected boolean blockStaleRequests = false;
-
-       /** Blame the SP if requests are malformed. */
-       protected boolean blameSP = false;
-
-       /**
-        * Time after which an authn request is considered stale(in seconds).
-        * Defaults to 30 minutes.
-        */
-       protected int requestTTL = 1800;
-
-       /** Protocol binding to use to the Authentication Assertion */
-       protected enum ENDPOINT_BINDING {
-               BROWSER_POST, ARTIFACT
-       };
-
-       /** ArtifactFactory used to make artifacts. */
-       protected SAMLArtifactFactory artifactFactory;
-
-       /** PRNG for Artifact assertionHandles. */
-       protected SecureRandom prng;
-
-       /**
-        * Default constructor.
-        */
-       public ShibbolethSSO() {
-
-               // setup SAML object builders
-
-               assertionBuilder = getBuilderFactory().getBuilder(
-                               Assertion.DEFAULT_ELEMENT_NAME);
-               authnStmtBuilder = getBuilderFactory().getBuilder(
-                               AuthenticationStatement.DEFAULT_ELEMENT_NAME);
-               subjectbuilder = getBuilderFactory().getBuilder(
-                               Subject.DEFAULT_ELEMENT_NAME);
-               subjConfBuilder = getBuilderFactory().getBuilder(
-                               SubjectConfirmation.DEFAULT_ELEMENT_NAME);
-               confMethodBuilder = getBuilderFactory().getBuilder(
-                               ConfirmationMethod.DEFAULT_ELEMENT_NAME);
-               nameIdentifierBuilder = getBuilderFactory().getBuilder(
-                               NameIdentifier.DEFAULT_ELEMENT_NAME);
-               audienceBuilder = getBuilderFactory().getBbuilder(
-                               Audience.DEFAULT_ELEMENT_NAME);
-               audienceRestrictionBuilder = getBuilderFactory().getBuilder(
-                               AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
-               statusBuilder = getBuilderFactory().getBuidler(
-                               Status.DEFAULT_ELEMENT_NAME);
-               statusCodeBuilder = getBuilderFactory().getBuilder(
-                               StatusCode.DEFAULT_ELEMENT_NAME);
-               statusMessageBuilder = getBuilderFactory().getBuilder(
-                               StatusMessage.DEFAULT_ELEMENT_NAME);
-               responseBuilder = getBuilderFactory().getBuilder(
-                               Response.DEFAULT_ELEMENT_NAME);
-
-               artifactFactory = new SAMLArtifactFactory();
-       }
-
-       /**
-        * Set the authentication manager.
-        * 
-        * @param authnManagerURL
-        *            The URL of the IdP's AuthenticationManager servlet
-        */
-       public void setAuthenticationManager(String authnManagerURL) {
-               authnMgrURL = authnManagerURL;
-       }
-
-       /**
-        * Set the RelyingPartyManager.
-        * 
-        * @param rpManager
-        *            A RelyingPartyManager.
-        */
-       public void setRelyingPartyManager(RelyingPartyManager rpManager) {
-               this.rpManager = rpManager;
-       }
-
-       /**
-        * Set the authentication method URI.
-        * 
-        * The URI SHOULD come from oasis-sstc-saml-core-1.1, section 7.1
-        * 
-        * @param authMethod
-        *            The authentication method's URI
-        */
-       public void setAuthenticationMethodURI(String authMethod) {
-               authenticationMethodURI = authMethod;
-       }
-
-       /**
-        * Set if old requests should be blocked.
-        * 
-        * @param blockStaleRequests
-        *            boolean flag.
-        */
-       public void setBlockStaleRequests(boolean blockStaleRequests) {
-               this.blockStaleRequests = blockStaleRequests;
-       }
-
-       /**
-        * Return if stale requests are blocked.
-        * 
-        * @return <code>true</code> if old requests are blocked.
-        */
-       public boolean getBlockStaleRequests() {
-               return blockStaleRequests;
-       }
-
-       /**
-        * Set request TTL.
-        * 
-        * @param ttl
-        *            Request timeout (in seconds).
-        */
-       public void setRequestTTL(int ttl) {
-               requestTTL = ttl;
-       }
-
-       /**
-        * Get Request TTL. This is the time after which a request is considered
-        * stale.
-        * 
-        * @return request timeout (in seconds).
-        */
-       public int getRequestTTL() {
-               return requestTTL;
-       }
-
-       /**
-        * Set the artifact map backing store.
-        * 
-        * @param artifactMap
-        *            the Artifact mapping backing store.
-        */
-       public void setArtifactMap(ArtifactMap artifactMap) {
-               this.artifactMap = artifactMap;
-       }
-
-       /**
-        * Get the artifact map backing store.
-        * 
-        * @return An ArtifactMap instance.
-        */
-       public ArtifactMap getArtifactMap() {
-               return 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());
-                       return false;
-               }
-
-               HttpServletRequest httpReq = (HttpServletRequest) request;
-               HttpServletResponse httpResp = (HttpServletResponse) response;
-               HttpSession httpSession = httpReq.getSession();
-               LoginContext loginCtx;
-
-               String shire = null;
-               String target = null;
-               String providerId = null;
-               String remoteAddr = null;
-
-               // extract the (mandatory) request parameters.
-               if (!getRequestParameters(httpReq, shire, target, providerId,
-                               remoteAddr)) {
-
-                       if (blameSP) {
-                               httpReq.setAttribute("errorPage", "/IdPErrorBlameSP.jsp");
-                               // XXX: flesh this out more.
-                       }
-
-                       return false;
-               }
-
-               // check for stale requests
-               if (blockStaleRequests) {
-                       String cookieName = getRPCookieName(providerName);
-                       if (!validateFreshness(httpReq, httpResp, cookieName)) {
-                               return false;
-                       }
-
-                       writeFreshnessCookie(httpReq, httpResp, cookieName);
-               }
-
-               // check if the user has already been authenticated
-               Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-               if (o == null) {
-
-                       // the user hasn't been authenticated, so forward the request
-                       // to the AuthenticationManager. When the AuthenticationManager
-                       // is done it will forward the request back to this servlet.
-
-                       // don't force reauth or passive auth
-                       loginCtx = new LoginContext(false, false);
-                       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 1 SSO request to AuthenticationManager",
-                                                               ex);
-                               return false;
-                       }
-               }
-
-               // The user has been authenticated.
-               // Process the SAML 1 authn request.
-
-               if (!(o instanceof LoginContext)) {
-                       log
-                                       .error("Invalid login context object -- object is not an instance of LoginContext.");
-                       return false;
-               }
-
-               loginCtx = (LoginContext) o;
-
-               if (!loginCtx.getAuthenticationOK()) {
-                       // issue error message.
-                       String failureMessage = loginCtx.getAuthenticationFailureMessage();
-
-                       // generate SAML failure message
-
-                       return true;
-               }
-
-               // The user successfully authenticated,
-               // so build the appropriate AuthenticationStatement.
-
-               DateTime now = new DateTime();
-               RelyingPartyConfiguration relyingParty = rpManager
-                               .getRelyingPartyConfiguration(providerId);
-               ShibbolethSSOConfiguration ssoConfig = relyingParty
-                               .getProfileConfigurations().get(
-                                               ShibbolethSSOConfiguration.PROFILE_ID);
-               SPSSODescriptor spDescriptor;
-
-               try {
-                       spDescriptor = rpManager.getMetadataProvider().getEntityDescriptor(
-                                       relyingParty.getRelyingPartyID()).getSPSSODescriptor(
-                                       SAML11_PROTOCOL_URI);
-               } catch (MetadataProviderException ex) {
-                       log.error("Unable to locate metadata for SP " + providerId
-                                       + " for protocol " + SAML11_PROTOCOL_URI, ex);
-                       return false;
-               }
-
-               if (spDescriptor == null) {
-                       log.error("Unable to locate metadata for SP " + providerId
-                                       + " for protocol " + SAML11_PROTOCOL_URI);
-                       // handle error
-                       return true;
-               }
-
-               // validate the AssertionConsumer URL
-               List<AssertionConsumerService> consumerEndpoints = validateAssertionConsumerURL(
-                               spDescriptor, shire);
-               if (consumerEndpoints.length == 0) {
-                       // handle error
-                       return true;
-               }
-
-               ENDPOINT_BINDING endpointBinding = getProtocolBinding(spDescriptor,
-                               consumerEndpoints, shire);
-
-               String confMethod;
-               if (endpointBinding = ENDPOINT_BINDING.BROWSER_POST) {
-                       confMethod = BEARER_CONF_METHOD_URI;
-               } else if (endpointBinding = ENDPOINT_BINDING.ARTIFACT) {
-                       confMethod = ARTIFACT_CONF_METHOD_URI;
-               }
-
-               Assertion authenticationAssertion = generateAuthenticationAssertion(
-                               loginCtx, relyingParty, ssoConfig, providerId, spDescriptor,
-                               confMethod, now);
-               if (authenticationAssertion == null) {
-                       // do error handling
-                       return true;
-               }
-
-               if (endpointBinging == ENDPOINT_BINDING.BROWSER_POST) {
-                       // do post
-               } else if (endpointBinding == ENDPOINT_BINDING.ARTIFACT) {
-                       respondWithArtifact(httpReq, httpResp, shire, target,
-                                       new Assertion[] { authenticationAssertion });
-               }
-
-               return true;
-       }
-
-       /**
-        * Respond with a SAML Artifact.
-        * 
-        * @param request
-        *            The HttpServletRequest.
-        * @param response
-        *            The HttpServletResponse.
-        * @param shire
-        *            The AssertionConsumerService URL.
-        * @parma target The target parameter from the request.
-        * @param assertions
-        *            One or more SAML assertions.
-        */
-       protected void respondWithArtifact(HttpServletRequest request,
-                       HttpServletResponse response, String shire, String target,
-                       RelyingPartyConfiguration relyingParty, Assertion[] assertions)
-                       throws ServletException, NoSuchProviderException {
-
-               if (assertions.length < 1) {
-                       return;
-               }
-
-               StringBuilder buf = new StringBuilder(shire);
-               buf.append("?TARGET=");
-               buf.append(URLEncoder.encode(target), "UTF-8");
-               ;
-
-               // We construct the type 1 Artifact's sourceID by SHA-1 hashing the
-               // IdP's providerID.
-               // This is legacy holdover from Shib 1.x.
-               MessageDigest digester = MessageDigest.getInstance("SHA-1");
-               byte[] sourceID = digester.digest(relyingParty.getProviderID);
-
-               for (Assertion assertion : assertions) {
-
-                       // XXX: todo: log the assertion to log4j @ debug level.
-
-                       byte artifactType = (byte) relyingParty.getDefaultArtifactType();
-
-                       SAMLArtifact artifact = artifactFactory.buildArtifact(SAML_VERSION,
-                                       new byte[] { 0, artifactType }, relyingParty
-                                                       .getProviderID());
-
-                       String artifactID = artifact.hexEncode();
-                       artifactMap.put(artifact, assertion);
-
-                       log.debug("encoding assertion " + assertion.getID()
-                                       + " into artifact " + artifactID);
-                       log.debug("appending artifact " + artifactID + " for URL " + shire);
-                       buf.append("&SAMLArt=");
-                       buf.append(URLEncoder.encode(artifact.base64Encode(), "UTF-8"));
-               }
-
-               String url = buf.toString();
-               response.sendRedirect(url);
-       }
-
-       /**
-        * Respond with the SAML 1 Browser/POST profile.
-        * 
-        * @param request
-        *            The HttpServletRequest.
-        * @param response
-        *            The HttpServletResponse.
-        * @param shire
-        *            The AssertionConsumerService URL.
-        * @parma target The target parameter from the request.
-        * @param assertions
-        *            One or more SAML assertions.
-        */
-       protected void respondWithPOST(HttpServletRequest request,
-                       HttpServletResponse response, String shire, String target,
-                       RelyingPartyConfiguration relyingParty, Assertion[] assertions)
-                       throws ServletException {
-
-               Response samlResponse = (Response) responseBuilder
-                               .buildObject(Response.DEFAULT_ELEMENT_NAME);
-               Status status = buildStatus("Success", null);
-               samlResponse.setStatus(status);
-               samlResponse.setIssueInstant(new DateTime());
-               samlResponse.setVersion(SAML_VERSION);
-               samlResponse.setID(getIdGenerator().generateIdentifier());
-               samlResponse.setRecipient(relyingParty.getRelyingPartyID());
-
-               List<Assertion> assertionList = samlResponse.getAssertions();
-               for (Assertion assertion : assertions) {
-                       assertionList.add(assertion);
-               }
-
-               request.setAttribute("acceptanceURL", shire);
-               request.setAttribute("target", target);
-
-               RequestDispatcher dispatcher = request
-                               .getRequestDispatcher("/IdP_SAML1_POST.jdp");
-               dispatcher.forward(request, response);
-       }
-
-       /**
-        * Get the Shibboleth profile-specific request parameters. The shire,
-        * target, providerId and remoteAddr parameters will be populated upon
-        * successful return.
-        * 
-        * @param request
-        *            The servlet request from the SP.
-        * @param shire
-        *            The AttributeConsumerService URL
-        * @param target
-        *            The location to which to POST the response.
-        * @param providerId
-        *            The SP's provider ID in the metadata.
-        * @param remoteAddr
-        *            The address of the requestor.
-        * 
-        * @return <code>true</code> if the request contains valid parameters.
-        */
-       protected boolean getRequestParameters(HttpServletRequest request,
-                       String shire, String target, String providerId, String remoteAddr) {
-
-               target = request.getParameter("target");
-               providerId = request.getParameter("providerId");
-               shire = request.getParameter("shire");
-               remoteAddr = request.getRemoteAddr();
-
-               if (target == null || target.equals("")) {
-                       log
-                                       .error("Shib 1 SSO request is missing or contains an invalid target parameter");
-                       return false;
-               }
-
-               if (providerId == null || providerId.equals("")) {
-                       log
-                                       .error("Shib 1 SSO request is missing or contains an invalid provierId parameter");
-                       return false;
-               }
-
-               if (shire == null || providerId.equals("")) {
-                       log
-                                       .error("Shib 1 SSO request is missing or contains an invalid shire parameter");
-                       return false;
-               }
-
-               if (remoteAddr == null || remoteAddr.equals("")) {
-                       log
-                                       .error("Unable to obtain requestor address when processing Shib 1 SSO request");
-                       return false;
-               }
-
-               return true;
-       }
-
-       /**
-        * Generate a SAML 1 AuthenticationStatement.
-        * 
-        * @param loginCtx
-        *            The LoginContext.
-        * @param relyingParty
-        *            The Replying Party configuration for the SP.
-        * @param ssoConfig
-        *            The ShibbolethSSOConfiguration data.
-        * @param spID
-        *            The providerID of the SP that sent the request.
-        * @param spDescriptor
-        *            The SPSSO Descriptor from the metadata.
-        * @param subjectConfirmationMethod
-        *            The SubjectConfirmationMethod. If <code>null</code> no
-        *            SubjectConfirmationMethod element will be generated.
-        * @param now
-        *            The current timestamp
-        * 
-        * @return A SAML 1 Authentication Assertion or <code>null</code> on
-        *         error.
-        */
-       protected Assertion generateAuthenticationAssertion(
-                       final LoginContext loginCtx,
-                       final RelyingPartyConfiguration relyingParty,
-                       final ShibbolethSSOConfiguration ssoConfig, String spID,
-                       final SPSSODescriptor spDescriptor,
-                       String subjectConfirmationMethod, final DateTime now) {
-
-               Assertion authenticationAssertion = (Assertion) assertionBuilder
-                               .build(Assertion.DEFAULT_ELEMENT_NAME);
-
-               authenticationAssertion.setIssueInstant(now);
-               authenticationAssertion.setVersion(SAMLVersion.VERSION_11);
-               authenticationAssertion.setIssuer(relyingParty.getProviderID());
-               authenticationAssertion.setID(getIdGenerator().generateIdentifier());
-               authenticationAssertion.setIssuer(relyingParty.getProviderID());
-
-               Conditions conditions = authenticationAssertion.getConditions();
-               conditions.setNotBefore(now.minusSeconds(30)); // for now, clock skew
-                                                                                                               // is hard-coded to 30
-                                                                                                               // seconds.
-               conditions.setNotOnOrAfter(now.plusMillis(ssoConfig
-                               .getAssertionLifetime()));
-
-               List<AudienceRestrictionCondition> audiences = conditions
-                               .getAudienceRestrictionConditions();
-               AudienceRestrictionCondition restrictionCondition = (AudienceRestrictionCondition) audienceRestrictionBuilder
-                               .buildObject(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
-               Audience rpAudience = (Audience) audienceBuilder
-                               .buildObject(Audience.DEFAULT_ELEMENT_NAME);
-               rpAudience.setURI(relyingParty.getProviderID());
-               audiences.add(rpAudience);
-               if (!relyingParty.getProviderID().equals(spID)) {
-                       Audience spAudience = (Audience) audienceBuilder
-                                       .buildObject(Audience.DEFAULT_ELEMENT_NAME);
-                       spAudience.setURI(spID);
-                       audiences.add(spAudience);
-               }
-
-               AuthenticationStatement authenticationStatement = (AuthenticationStatement) authnStmtBuilder
-                               .buildObject(AuthenticationStatement.DEFAULT_ELEMENT_NAME);
-
-               authenticationStatement.setSubject(buildSubject(loginCtx,
-                               subjectConfirmationMethod, relyingParty));
-               authenticationStatement.setAuthenticationInstant(loginCtx
-                               .getAuthenticationInstant());
-               authenticationStatement
-                               .setAuthenticationMethod(authenticationMethodURI);
-
-               authenticationAssertion.getAuthenticationStatements().add(
-                               authenticationStatement);
-
-               if (spDescriptor.getWantAssertionsSigned()) {
-                       // sign the assertion
-               }
-
-               return authenticationStatement;
-       }
-
-       /**
-        * Get the protocol binding to use for sending the authentication assertion.
-        * Currently, only Browser/POST and Artifact are supported. This method will
-        * return the first recognized binding that it locates.
-        * 
-        * @param spDescriptor
-        *            The SP's SPSSODescriptor
-        * @param endpoints
-        *            The list of AssertionConsumerEndpoints with the "shire" URL as
-        *            their location.
-        * @param shireURL
-        *            The "shire" url from the authn request.
-        * 
-        * @return The protocol binding for a given SPSSODescriptor.
-        * 
-        * @throws MetadataException
-        *             if no Browswer/POST or Artifact binding can be found.
-        */
-       protected ENDPOINT_BINDING getProtocolBinding(
-                       final SPSSODescriptor spDecsriptor,
-                       final List<AssertionConsumerService> endpoints, String shireURL)
-                       throws MetadataException {
-
-               // check the default AssertionConsumerService first.
-               AssertionConsumerService defaultConsumer = spDescriptor
-                               .getDefaultAssertionConsumerService();
-
-               if (defaultConsumer != null
-                               && defaultConsumer.getLocation().equals(acceptanceURL)) {
-
-                       if (defaultConsumer.getBinding().equals(PROFILE_ARTIFACT_URI)) {
-                               return ENDPOINT_BINDING.ARTIFACT;
-                       } else if (defaultConsumer.getBinding().equals(
-                                       PROFILE_BROWSER_POST_URI)) {
-                               return ENDPOINT_BINDING.BROWSER_POST;
-                       }
-               }
-
-               // check the (already filtered) list of AssertionConsumer endpoints
-               for (AssertionConsumerService endpoint : endpoints) {
-                       if (endpoint.getBinding().equals(PROFILE_ARTIFACT_URI)) {
-                               return ENDPOINT_BINDING.ARTIFACT;
-                       } else if (endpoint.getBinding().equals(PROFILE_BROWSER_POST_URI)) {
-                               return ENDPOINT_BINDING.BROWSER_POST;
-                       }
-               }
-
-               // no AssertionConsumerServices were found, or none had a recognized
-               // binding
-               log
-                               .error("Unable to find a Browswer/POST or Artifact binding "
-                                               + " for an AssertionConsumerService in "
-                                               + spDecsriptor.getID());
-
-               throw new MetadataException(
-                               "Unable to find a Browswer/POST or Artifact binding "
-                                               + " for an AssertionConsumerService in "
-                                               + spDecsriptor.getID());
-       }
-
-       /**
-        * Sign an XMLObject.
-        * 
-        * @param object
-        *            The XMLObject to be signed
-        */
-       protected void SignXMLObject(final SignableXMLObject object)
-                       throws KeyException {
-               // sign the object
-       }
-
-       /**
-        * Validate the AssertionConsumer ("shire") URL against the metadata.
-        * 
-        * @param spDescriptor
-        *            The SPSSO element from the metadata
-        * @param URL
-        *            The "shire" URL.
-        * 
-        * @return a {@link List} of AssertionConsumerServices which have
-        *         <code>url</code> as their location.
-        */
-       protected List<AssertionConsumerService> validateAssertionConsumerURL(
-                       final SPSSODescriptor spDescriptor, String url) {
-
-               // spDescriptor returns a reference to an internal mutable copy, so make
-               // a copy of it.
-               List<AssertionConsumerService> consumerURLs = new FastList<AssertionConsumerService>();
-
-               // filter out any list elements that don't have the correct location
-               // field
-               // copy any consumerURLs with the correct location
-               for (AssertionConsumerService service : spDescriptor
-                               .getAssertionConsumerServices()) {
-                       if (service.getLocation().equals(url)) {
-                               consumerURLs.add(service);
-                       }
-               }
-
-               return consumerURLs;
-       }
-
-       /**
-        * Validate the "freshness" of an authn request. If the reqeust is more than
-        * 30 minutes old, reject it.
-        * 
-        * @param request
-        *            The HttpServletRequest
-        * @param response
-        *            The HttpServletResponse
-        * @param cookieName
-        *            The name of the RP's cookie.
-        * 
-        * @return <code>true</code> if the cookie is fresh; otherwise
-        *         <code>false</code>
-        */
-       protected boolean validateFreshness(HttpServletRequest request,
-                       HttpServletResponse response, String cookieName)
-                       throws IOException, ServletException {
-
-               if (cookieName == null) {
-                       return false;
-               }
-
-               String timestamp = request.getParameter("time");
-               if (timestamp == null || timestamp.equals("")) {
-                       return true;
-               }
-
-               long reqtime;
-               try {
-                       reqtime = Long.parseLong(timestamp);
-               } catch (NumberFormatException ex) {
-                       log.error("Unable to parse Authentication Request's timestamp", ex);
-                       return false;
-               }
-
-               if (reqtime * 1000 < System.currentTimeMillis() - requestTTL * 1000) {
-                       RequestDispatcher rd = request
-                                       .getRequestDispatcher("/IdPStale.jsp");
-                       rd.forward(request, response);
-                       return false;
-               }
-
-               for (Cookie cookie : request.getCookies()) {
-                       if (cookieName.equals(cookie.getName())) {
-                               try {
-                                       long cookieTime = Long.parseLong(cookie.getValue());
-                                       if (reqtime <= cookieTime) {
-                                               RequestDispatcher rd = request
-                                                               .getRequestDispatcher("/IdPStale.jsp");
-                                               rd.forward(request, response);
-                                               return false;
-                                       }
-                               } catch (NumberFormatException ex) {
-                                       log.error("Unable to parse freshness cookie's timestamp",
-                                                       ex);
-                                       return false;
-                               }
-                       }
-               }
-
-               return true;
-       }
-
-       /**
-        * Generate the RP's cookie name
-        * 
-        * @param providerID
-        *            The RP's providerID
-        * 
-        * @throws NoSuchAlgorithmException
-        *             If unable to find a JCE provider for SHA-1
-        * 
-        * @return the RP's cookie name
-        */
-       protected String getRPCookieName(String providerID)
-                       throws NoSuchAlgorithmException {
-
-               MessageDigest digester = MessageDigest
-                               .getInstance(RP_COOKIE_DIGEST_ALG);
-               return "shib_sp_"
-                               + new String(Hex.encode(digester.digest(providerID
-                                               .getBytes("UTF-8"))));
-       }
-
-       /**
-        * Write the current time into the freshness cookie.
-        */
-       protected void writeFreshnessCookie(HttpServletRequest request,
-                       HttpServletResponse response, String cookieName) {
-
-               String timestamp = request.getParameter("time");
-               if (timestamp == null || timestamp.equals("")) {
-                       return;
-               }
-
-               Cookie cookie = new Cookie(cookieName, timestamp);
-               cookie.setSecure(true);
-               response.addCookie(cookie);
-       }
-
-       /**
-        * Generate a SAML 1 Subject element.
-        * 
-        * @param loginContext
-        *            The LoginContext for an authenticated user.
-        * @param confirmationMethod
-        *            The SubjectConfirmationMethod URI, or <code>null</code> is
-        *            none is to be set.
-        * @param relyingParty
-        *            The RelyingPartyConfiguration for the request.
-        * 
-        * @return a Subject object.
-        */
-       protected Subject buildSubject(final LoginContext loginCtx,
-                       String confirmationMethod,
-                       final RelyingPartyConfiguration relyingParty) {
-
-               Subject subject = (Subject) subjectBuilder
-                               .buildObject(Subject.DEFAULT_ELEMENT_NAME);
-
-               NameIdentifier nameID = (NameIdentifier) nameIdentifierBuilder
-                               .buildObject(NameIdentifier.DEFAULT_ELEMENT_NAME);
-               nameID.setFormat(relyingParty.getDefaultNameIDFormat());
-               String username = loginCtx.getUserID();
-               // XXX: todo: map the username onto an appropriate format
-               nameID.setNameQualifier(username);
-
-               if (subjectConfirmationMethod != null) {
-
-                       SubjectConfirmation subjConf = (SubjectConfirmation) subjConfBuilder
-                                       .buildObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
-
-                       ConfirmationMethod m = (ConfirmationMethod) confMethodBuilder
-                                       .buildObject(ConfirmationMethod.DEFAULT_ELEMENT_NAME);
-
-                       m.setConfirmationMethod(subjectConfirmationMethod);
-                       subjConf.getConfirmationMethods().add(m);
-                       subject.setSubjectConfirmation(subjConf);
-               }
-
-               return subject;
-       }
-
-       /**
-        * Build a SAML 1 Status element.
-        * 
-        * @param statusCode
-        *            The status code - see oasis-sstc-saml-core-1.1, section
-        *            3.4.3.1.
-        * @param statusMessage
-        *            The status message, or <code>null</code> if none is to be
-        *            set.
-        * 
-        * @return The Status object, or <code>null</code> on error.
-        */
-       protected Status buildStatus(String statusCode, String statusMessage) {
-
-               if (statusCode == null || statusCode.equals("")) {
-                       return null;
-               }
-
-               Status status = (Status) statusBuilder
-                               .buildObject(Status.DEFAULT_ELEMENT_NAME);
-               StatusCode sc = (StatusCode) statusCodeBuilder
-                               .buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
-               sc.setValue(statusCode);
-               status.setStatusCode(sc);
-
-               if (statusMessage != null || !(statusMessage.equals(""))) {
-
-                       StatusMessage sm = (StatusMessage) statusMessageBuilder
-                                       .buildObject(StatusMessage.DEFAULT_ELEMENT_NAME);
-                       sm.setMessage(statusMessage);
-                       status.setStatusMessage(sm);
-               }
-
-               return status;
-       }
-
-       /**
-        * Get an Attribute Statement.
-        * 
-        * @param rpConfig
-        *            The RelyingPartyConfiguration for the request.
-        * @param subject
-        *            The Subject of the request.
-        * @param request
-        *            The ServletRequest.
-        * 
-        * @return An AttributeStatement.
-        * 
-        * @throws ServletException
-        *             On error.
-        */
-       protected AttributeStatement getAttributeStatement(
-                       RelyingPartyConfiguration rpConfig, Subject subject,
-                       ServletRequest request) throws ServletException {
-
-               // build a dummy AttributeQuery object for the AA.
-
-               AttributeAuthority aa = new AttributeAuthority();
-               aa.setAttributeResolver(getAttributeResolver());
-               aa.setFilteringEngine(getFilteringEngine());
-               // aa.setSecurityPolicy(getDecoder().getSecurityPolicy()); //
-               // super.getDecoder() will need to change.
-               aa.setRequest(request);
-               aa.setRelyingPartyConfiguration(rpConfig);
-               AttributeStatement statement = null;
-               try {
-                       statement = aa.performAttributeQuery(message);
-               } catch (AttributeResolutionException e) {
-                       log.error("Error resolving attributes", e);
-                       throw new ServletException("Error resolving attributes");
-               } catch (FilteringException e) {
-                       log.error("Error filtering attributes", e);
-                       throw new ServletException("Error filtering attributes");
-               }
-
-               return statement;
-       }
+    /** Builder for Audience elements. */
+    protected XMLObjectBuilder audienceBuilder;
+
+    /** Builder for AudienceRestrictionCondition elements. */
+    protected XMLObjectBuilder audienceRestrictionBuilder;
+
+    /** Builder for Assertions. */
+    protected XMLObjectBuilder assertionBuilder;
+
+    /** Builder for Status objects. */
+    protected XMLObjectBuilder statusBuilder;
+
+    /** Builder for StatusCode objects. */
+    protected XMLObjectBuilder statusCodeBuilder;
+
+    /** Builder for StatusMessage objects. */
+    protected XMLObjectBuilder statusMessageBuilder;
+
+    /** Builder for Response objects. */
+    protected XMLObjectbuilder responseBuilder;
+
+    /** Block stale requests. */
+    protected boolean blockStaleRequests = false;
+
+    /** Blame the SP if requests are malformed. */
+    protected boolean blameSP = false;
+
+    /**
+     * Time after which an authn request is considered stale(in seconds). Defaults to 30 minutes.
+     */
+    protected int requestTTL = 1800;
+
+    /** Protocol binding to use to the Authentication Assertion */
+    protected enum ENDPOINT_BINDING {
+        BROWSER_POST, ARTIFACT
+    };
+
+    /** ArtifactFactory used to make artifacts. */
+    protected SAMLArtifactFactory artifactFactory;
+
+    /** PRNG for Artifact assertionHandles. */
+    protected SecureRandom prng;
+
+    /**
+     * Default constructor.
+     */
+    public ShibbolethSSO() {
+
+        // setup SAML object builders
+
+        assertionBuilder = getBuilderFactory().getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
+        authnStmtBuilder = getBuilderFactory().getBuilder(AuthenticationStatement.DEFAULT_ELEMENT_NAME);
+        subjectbuilder = getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
+        subjConfBuilder = getBuilderFactory().getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
+        confMethodBuilder = getBuilderFactory().getBuilder(ConfirmationMethod.DEFAULT_ELEMENT_NAME);
+        nameIdentifierBuilder = getBuilderFactory().getBuilder(NameIdentifier.DEFAULT_ELEMENT_NAME);
+        audienceBuilder = getBuilderFactory().getBbuilder(Audience.DEFAULT_ELEMENT_NAME);
+        audienceRestrictionBuilder = getBuilderFactory().getBuilder(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
+        statusBuilder = getBuilderFactory().getBuidler(Status.DEFAULT_ELEMENT_NAME);
+        statusCodeBuilder = getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
+        statusMessageBuilder = getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
+        responseBuilder = getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
+
+        artifactFactory = new SAMLArtifactFactory();
+    }
+
+    /**
+     * Set the authentication manager.
+     * 
+     * @param authnManagerURL The URL of the IdP's AuthenticationManager servlet
+     */
+    public void setAuthenticationManager(String authnManagerURL) {
+        authnMgrURL = authnManagerURL;
+    }
+
+    /**
+     * Set the RelyingPartyManager.
+     * 
+     * @param rpManager A RelyingPartyManager.
+     */
+    public void setRelyingPartyManager(RelyingPartyManager rpManager) {
+        this.rpManager = rpManager;
+    }
+
+    /**
+     * Set the authentication method URI.
+     * 
+     * The URI SHOULD come from oasis-sstc-saml-core-1.1, section 7.1
+     * 
+     * @param authMethod The authentication method's URI
+     */
+    public void setAuthenticationMethodURI(String authMethod) {
+        authenticationMethodURI = authMethod;
+    }
+
+    /**
+     * Set if old requests should be blocked.
+     * 
+     * @param blockStaleRequests boolean flag.
+     */
+    public void setBlockStaleRequests(boolean blockStaleRequests) {
+        this.blockStaleRequests = blockStaleRequests;
+    }
+
+    /**
+     * Return if stale requests are blocked.
+     * 
+     * @return <code>true</code> if old requests are blocked.
+     */
+    public boolean getBlockStaleRequests() {
+        return blockStaleRequests;
+    }
+
+    /**
+     * Set request TTL.
+     * 
+     * @param ttl Request timeout (in seconds).
+     */
+    public void setRequestTTL(int ttl) {
+        requestTTL = ttl;
+    }
+
+    /**
+     * Get Request TTL. This is the time after which a request is considered stale.
+     * 
+     * @return request timeout (in seconds).
+     */
+    public int getRequestTTL() {
+        return requestTTL;
+    }
+
+    /**
+     * Set the artifact map backing store.
+     * 
+     * @param artifactMap the Artifact mapping backing store.
+     */
+    public void setArtifactMap(ArtifactMap artifactMap) {
+        this.artifactMap = artifactMap;
+    }
+
+    /**
+     * Get the artifact map backing store.
+     * 
+     * @return An ArtifactMap instance.
+     */
+    public ArtifactMap getArtifactMap() {
+        return artifactMap;
+    }
+
+    /** {@inheritDoc} */
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
+
+        // Only http servlets are supported for now.
+        if (!(request.getRequest() instanceof HttpServletRequest)) {
+            log.error("Received a non-HTTP request from " + request.getRequest().getRemoteHost());
+            return false;
+        }
+
+        HttpServletRequest httpReq = (HttpServletRequest) request.getRequest();
+        HttpServletResponse httpResp = (HttpServletResponse) response.getResponse();
+        HttpSession httpSession = httpReq.getSession();
+        LoginContext loginCtx;
+
+        String shire = null;
+        String target = null;
+        String providerId = null;
+        String remoteAddr = null;
+
+        // extract the (mandatory) request parameters.
+        if (!getRequestParameters(httpReq, shire, target, providerId, remoteAddr)) {
+
+            if (blameSP) {
+                httpReq.setAttribute("errorPage", "/IdPErrorBlameSP.jsp");
+                // XXX: flesh this out more.
+            }
+
+            return false;
+        }
+
+        // check for stale requests
+        if (blockStaleRequests) {
+            String cookieName = getRPCookieName(providerName);
+            if (!validateFreshness(httpReq, httpResp, cookieName)) {
+                return false;
+            }
+
+            writeFreshnessCookie(httpReq, httpResp, cookieName);
+        }
+
+        // check if the user has already been authenticated
+        Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+        if (o == null) {
+
+            // the user hasn't been authenticated, so forward the request
+            // to the AuthenticationManager. When the AuthenticationManager
+            // is done it will forward the request back to this servlet.
+
+            // don't force reauth or passive auth
+            loginCtx = new LoginContext(false, false);
+            loginCtx.setProfileHandlerURL(httpReq.getPathInfo());
+            httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginCtx);
+            try {
+                RequestDispatcher dispatcher = request.getRequest().getRequestDispatcher(authnMgrURL);
+                dispatcher.forward(request.getRequest(), response.getResponse());
+            } catch (IOException ex) {
+                log.error("Error forwarding SAML 1 SSO request to AuthenticationManager", ex);
+                return false;
+            }
+        }
+
+        // The user has been authenticated.
+        // Process the SAML 1 authn request.
+
+        if (!(o instanceof LoginContext)) {
+            log.error("Invalid login context object -- object is not an instance of LoginContext.");
+            return false;
+        }
+
+        loginCtx = (LoginContext) o;
+
+        if (!loginCtx.getAuthenticationOK()) {
+            // issue error message.
+            String failureMessage = loginCtx.getAuthenticationFailureMessage();
+
+            // generate SAML failure message
+
+            return true;
+        }
+
+        // The user successfully authenticated,
+        // so build the appropriate AuthenticationStatement.
+
+        DateTime now = new DateTime();
+        RelyingPartyConfiguration relyingParty = rpManager.getRelyingPartyConfiguration(providerId);
+        ShibbolethSSOConfiguration ssoConfig = relyingParty.getProfileConfigurations().get(
+                ShibbolethSSOConfiguration.PROFILE_ID);
+        SPSSODescriptor spDescriptor;
+
+        try {
+            spDescriptor = rpManager.getMetadataProvider().getEntityDescriptor(relyingParty.getRelyingPartyID())
+                    .getSPSSODescriptor(SAML11_PROTOCOL_URI);
+        } catch (MetadataProviderException ex) {
+            log.error("Unable to locate metadata for SP " + providerId + " for protocol " + SAML11_PROTOCOL_URI, ex);
+            return false;
+        }
+
+        if (spDescriptor == null) {
+            log.error("Unable to locate metadata for SP " + providerId + " for protocol " + SAML11_PROTOCOL_URI);
+            // handle error
+            return true;
+        }
+
+        // validate the AssertionConsumer URL
+        List<AssertionConsumerService> consumerEndpoints = validateAssertionConsumerURL(spDescriptor, shire);
+        if (consumerEndpoints.length == 0) {
+            // handle error
+            return true;
+        }
+
+        ENDPOINT_BINDING endpointBinding = getProtocolBinding(spDescriptor, consumerEndpoints, shire);
+
+        String confMethod;
+        if (endpointBinding = ENDPOINT_BINDING.BROWSER_POST) {
+            confMethod = BEARER_CONF_METHOD_URI;
+        } else if (endpointBinding = ENDPOINT_BINDING.ARTIFACT) {
+            confMethod = ARTIFACT_CONF_METHOD_URI;
+        }
+
+        Assertion authenticationAssertion = generateAuthenticationAssertion(loginCtx, relyingParty, ssoConfig,
+                providerId, spDescriptor, confMethod, now);
+        if (authenticationAssertion == null) {
+            // do error handling
+            return true;
+        }
+
+        if (endpointBinging == ENDPOINT_BINDING.BROWSER_POST) {
+            // do post
+        } else if (endpointBinding == ENDPOINT_BINDING.ARTIFACT) {
+            respondWithArtifact(httpReq, httpResp, shire, target, new Assertion[] { authenticationAssertion });
+        }
+
+        return true;
+    }
+
+    /**
+     * Respond with a SAML Artifact.
+     * 
+     * @param request The HttpServletRequest.
+     * @param response The HttpServletResponse.
+     * @param shire The AssertionConsumerService URL.
+     * @parma target The target parameter from the request.
+     * @param assertions One or more SAML assertions.
+     */
+    protected void respondWithArtifact(HttpServletRequest request, HttpServletResponse response, String shire,
+            String target, RelyingPartyConfiguration relyingParty, Assertion[] assertions) throws ServletException,
+            NoSuchProviderException {
+
+        if (assertions.length < 1) {
+            return;
+        }
+
+        StringBuilder buf = new StringBuilder(shire);
+        buf.append("?TARGET=");
+        buf.append(URLEncoder.encode(target), "UTF-8");;
+
+        // We construct the type 1 Artifact's sourceID by SHA-1 hashing the
+        // IdP's providerID.
+        // This is legacy holdover from Shib 1.x.
+        MessageDigest digester = MessageDigest.getInstance("SHA-1");
+        byte[] sourceID = digester.digest(relyingParty.getProviderID);
+
+        for (Assertion assertion : assertions) {
+
+            // XXX: todo: log the assertion to log4j @ debug level.
+
+            byte artifactType = (byte) relyingParty.getDefaultArtifactType();
+
+            SAMLArtifact artifact = artifactFactory.buildArtifact(SAML_VERSION, new byte[] { 0, artifactType },
+                    relyingParty.getProviderID());
+
+            String artifactID = artifact.hexEncode();
+            artifactMap.put(artifact, assertion);
+
+            log.debug("encoding assertion " + assertion.getID() + " into artifact " + artifactID);
+            log.debug("appending artifact " + artifactID + " for URL " + shire);
+            buf.append("&SAMLArt=");
+            buf.append(URLEncoder.encode(artifact.base64Encode(), "UTF-8"));
+        }
+
+        String url = buf.toString();
+        response.sendRedirect(url);
+    }
+
+    /**
+     * Respond with the SAML 1 Browser/POST profile.
+     * 
+     * @param request The HttpServletRequest.
+     * @param response The HttpServletResponse.
+     * @param shire The AssertionConsumerService URL.
+     * @parma target The target parameter from the request.
+     * @param assertions One or more SAML assertions.
+     */
+    protected void respondWithPOST(HttpServletRequest request, HttpServletResponse response, String shire,
+            String target, RelyingPartyConfiguration relyingParty, Assertion[] assertions) throws ServletException {
+
+        Response samlResponse = (Response) responseBuilder.buildObject(Response.DEFAULT_ELEMENT_NAME);
+        Status status = buildStatus("Success", null);
+        samlResponse.setStatus(status);
+        samlResponse.setIssueInstant(new DateTime());
+        samlResponse.setVersion(SAML_VERSION);
+        samlResponse.setID(getIdGenerator().generateIdentifier());
+        samlResponse.setRecipient(relyingParty.getRelyingPartyID());
+
+        List<Assertion> assertionList = samlResponse.getAssertions();
+        for (Assertion assertion : assertions) {
+            assertionList.add(assertion);
+        }
+
+        request.setAttribute("acceptanceURL", shire);
+        request.setAttribute("target", target);
+
+        RequestDispatcher dispatcher = request.getRequestDispatcher("/IdP_SAML1_POST.jdp");
+        dispatcher.forward(request, response);
+    }
+
+    /**
+     * Get the Shibboleth profile-specific request parameters. The shire, target, providerId and remoteAddr parameters
+     * will be populated upon successful return.
+     * 
+     * @param request The servlet request from the SP.
+     * @param shire The AttributeConsumerService URL
+     * @param target The location to which to POST the response.
+     * @param providerId The SP's provider ID in the metadata.
+     * @param remoteAddr The address of the requestor.
+     * 
+     * @return <code>true</code> if the request contains valid parameters.
+     */
+    protected boolean getRequestParameters(HttpServletRequest request, String shire, String target, String providerId,
+            String remoteAddr) {
+
+        target = request.getParameter("target");
+        providerId = request.getParameter("providerId");
+        shire = request.getParameter("shire");
+        remoteAddr = request.getRemoteAddr();
+
+        if (target == null || target.equals("")) {
+            log.error("Shib 1 SSO request is missing or contains an invalid target parameter");
+            return false;
+        }
+
+        if (providerId == null || providerId.equals("")) {
+            log.error("Shib 1 SSO request is missing or contains an invalid provierId parameter");
+            return false;
+        }
+
+        if (shire == null || providerId.equals("")) {
+            log.error("Shib 1 SSO request is missing or contains an invalid shire parameter");
+            return false;
+        }
+
+        if (remoteAddr == null || remoteAddr.equals("")) {
+            log.error("Unable to obtain requestor address when processing Shib 1 SSO request");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Generate a SAML 1 AuthenticationStatement.
+     * 
+     * @param loginCtx The LoginContext.
+     * @param relyingParty The Replying Party configuration for the SP.
+     * @param ssoConfig The ShibbolethSSOConfiguration data.
+     * @param spID The providerID of the SP that sent the request.
+     * @param spDescriptor The SPSSO Descriptor from the metadata.
+     * @param subjectConfirmationMethod The SubjectConfirmationMethod. If <code>null</code> no
+     *            SubjectConfirmationMethod element will be generated.
+     * @param now The current timestamp
+     * 
+     * @return A SAML 1 Authentication Assertion or <code>null</code> on error.
+     */
+    protected Assertion generateAuthenticationAssertion(final LoginContext loginCtx,
+            final RelyingPartyConfiguration relyingParty, final ShibbolethSSOConfiguration ssoConfig, String spID,
+            final SPSSODescriptor spDescriptor, String subjectConfirmationMethod, final DateTime now) {
+
+        Assertion authenticationAssertion = (Assertion) assertionBuilder.build(Assertion.DEFAULT_ELEMENT_NAME);
+
+        authenticationAssertion.setIssueInstant(now);
+        authenticationAssertion.setVersion(SAMLVersion.VERSION_11);
+        authenticationAssertion.setIssuer(relyingParty.getProviderID());
+        authenticationAssertion.setID(getIdGenerator().generateIdentifier());
+        authenticationAssertion.setIssuer(relyingParty.getProviderID());
+
+        Conditions conditions = authenticationAssertion.getConditions();
+        conditions.setNotBefore(now.minusSeconds(30)); // for now, clock skew
+        // is hard-coded to 30
+        // seconds.
+        conditions.setNotOnOrAfter(now.plusMillis(ssoConfig.getAssertionLifetime()));
+
+        List<AudienceRestrictionCondition> audiences = conditions.getAudienceRestrictionConditions();
+        AudienceRestrictionCondition restrictionCondition = (AudienceRestrictionCondition) audienceRestrictionBuilder
+                .buildObject(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
+        Audience rpAudience = (Audience) audienceBuilder.buildObject(Audience.DEFAULT_ELEMENT_NAME);
+        rpAudience.setURI(relyingParty.getProviderID());
+        audiences.add(rpAudience);
+        if (!relyingParty.getProviderID().equals(spID)) {
+            Audience spAudience = (Audience) audienceBuilder.buildObject(Audience.DEFAULT_ELEMENT_NAME);
+            spAudience.setURI(spID);
+            audiences.add(spAudience);
+        }
+
+        AuthenticationStatement authenticationStatement = (AuthenticationStatement) authnStmtBuilder
+                .buildObject(AuthenticationStatement.DEFAULT_ELEMENT_NAME);
+
+        authenticationStatement.setSubject(buildSubject(loginCtx, subjectConfirmationMethod, relyingParty));
+        authenticationStatement.setAuthenticationInstant(loginCtx.getAuthenticationInstant());
+        authenticationStatement.setAuthenticationMethod(authenticationMethodURI);
+
+        authenticationAssertion.getAuthenticationStatements().add(authenticationStatement);
+
+        if (spDescriptor.getWantAssertionsSigned()) {
+            // sign the assertion
+        }
+
+        return authenticationStatement;
+    }
+
+    /**
+     * Get the protocol binding to use for sending the authentication assertion. Currently, only Browser/POST and
+     * Artifact are supported. This method will return the first recognized binding that it locates.
+     * 
+     * @param spDescriptor The SP's SPSSODescriptor
+     * @param endpoints The list of AssertionConsumerEndpoints with the "shire" URL as their location.
+     * @param shireURL The "shire" url from the authn request.
+     * 
+     * @return The protocol binding for a given SPSSODescriptor.
+     * 
+     * @throws MetadataException if no Browswer/POST or Artifact binding can be found.
+     */
+    protected ENDPOINT_BINDING getProtocolBinding(final SPSSODescriptor spDecsriptor,
+            final List<AssertionConsumerService> endpoints, String shireURL) throws MetadataException {
+
+        // check the default AssertionConsumerService first.
+        AssertionConsumerService defaultConsumer = spDescriptor.getDefaultAssertionConsumerService();
+
+        if (defaultConsumer != null && defaultConsumer.getLocation().equals(acceptanceURL)) {
+
+            if (defaultConsumer.getBinding().equals(PROFILE_ARTIFACT_URI)) {
+                return ENDPOINT_BINDING.ARTIFACT;
+            } else if (defaultConsumer.getBinding().equals(PROFILE_BROWSER_POST_URI)) {
+                return ENDPOINT_BINDING.BROWSER_POST;
+            }
+        }
+
+        // check the (already filtered) list of AssertionConsumer endpoints
+        for (AssertionConsumerService endpoint : endpoints) {
+            if (endpoint.getBinding().equals(PROFILE_ARTIFACT_URI)) {
+                return ENDPOINT_BINDING.ARTIFACT;
+            } else if (endpoint.getBinding().equals(PROFILE_BROWSER_POST_URI)) {
+                return ENDPOINT_BINDING.BROWSER_POST;
+            }
+        }
+
+        // no AssertionConsumerServices were found, or none had a recognized
+        // binding
+        log.error("Unable to find a Browswer/POST or Artifact binding " + " for an AssertionConsumerService in "
+                + spDecsriptor.getID());
+
+        throw new MetadataException("Unable to find a Browswer/POST or Artifact binding "
+                + " for an AssertionConsumerService in " + spDecsriptor.getID());
+    }
+
+    /**
+     * Sign an XMLObject.
+     * 
+     * @param object The XMLObject to be signed
+     */
+    protected void SignXMLObject(final SignableXMLObject object) throws KeyException {
+        // sign the object
+    }
+
+    /**
+     * Validate the AssertionConsumer ("shire") URL against the metadata.
+     * 
+     * @param spDescriptor The SPSSO element from the metadata
+     * @param URL The "shire" URL.
+     * 
+     * @return a {@link List} of AssertionConsumerServices which have <code>url</code> as their location.
+     */
+    protected List<AssertionConsumerService> validateAssertionConsumerURL(final SPSSODescriptor spDescriptor, String url) {
+
+        // spDescriptor returns a reference to an internal mutable copy, so make
+        // a copy of it.
+        List<AssertionConsumerService> consumerURLs = new FastList<AssertionConsumerService>();
+
+        // filter out any list elements that don't have the correct location
+        // field
+        // copy any consumerURLs with the correct location
+        for (AssertionConsumerService service : spDescriptor.getAssertionConsumerServices()) {
+            if (service.getLocation().equals(url)) {
+                consumerURLs.add(service);
+            }
+        }
+
+        return consumerURLs;
+    }
+
+    /**
+     * Validate the "freshness" of an authn request. If the reqeust is more than 30 minutes old, reject it.
+     * 
+     * @param request The HttpServletRequest
+     * @param response The HttpServletResponse
+     * @param cookieName The name of the RP's cookie.
+     * 
+     * @return <code>true</code> if the cookie is fresh; otherwise <code>false</code>
+     */
+    protected boolean validateFreshness(HttpServletRequest request, HttpServletResponse response, String cookieName)
+            throws IOException, ServletException {
+
+        if (cookieName == null) {
+            return false;
+        }
+
+        String timestamp = request.getParameter("time");
+        if (timestamp == null || timestamp.equals("")) {
+            return true;
+        }
+
+        long reqtime;
+        try {
+            reqtime = Long.parseLong(timestamp);
+        } catch (NumberFormatException ex) {
+            log.error("Unable to parse Authentication Request's timestamp", ex);
+            return false;
+        }
+
+        if (reqtime * 1000 < System.currentTimeMillis() - requestTTL * 1000) {
+            RequestDispatcher rd = request.getRequestDispatcher("/IdPStale.jsp");
+            rd.forward(request, response);
+            return false;
+        }
+
+        for (Cookie cookie : request.getCookies()) {
+            if (cookieName.equals(cookie.getName())) {
+                try {
+                    long cookieTime = Long.parseLong(cookie.getValue());
+                    if (reqtime <= cookieTime) {
+                        RequestDispatcher rd = request.getRequestDispatcher("/IdPStale.jsp");
+                        rd.forward(request, response);
+                        return false;
+                    }
+                } catch (NumberFormatException ex) {
+                    log.error("Unable to parse freshness cookie's timestamp", ex);
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Generate the RP's cookie name
+     * 
+     * @param providerID The RP's providerID
+     * 
+     * @throws NoSuchAlgorithmException If unable to find a JCE provider for SHA-1
+     * 
+     * @return the RP's cookie name
+     */
+    protected String getRPCookieName(String providerID) throws NoSuchAlgorithmException {
+
+        MessageDigest digester = MessageDigest.getInstance(RP_COOKIE_DIGEST_ALG);
+        return "shib_sp_" + new String(Hex.encode(digester.digest(providerID.getBytes("UTF-8"))));
+    }
+
+    /**
+     * Write the current time into the freshness cookie.
+     */
+    protected void writeFreshnessCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) {
+
+        String timestamp = request.getParameter("time");
+        if (timestamp == null || timestamp.equals("")) {
+            return;
+        }
+
+        Cookie cookie = new Cookie(cookieName, timestamp);
+        cookie.setSecure(true);
+        response.addCookie(cookie);
+    }
+
+    /**
+     * Generate a SAML 1 Subject element.
+     * 
+     * @param loginContext The LoginContext for an authenticated user.
+     * @param confirmationMethod The SubjectConfirmationMethod URI, or <code>null</code> is none is to be set.
+     * @param relyingParty The RelyingPartyConfiguration for the request.
+     * 
+     * @return a Subject object.
+     */
+    protected Subject buildSubject(final LoginContext loginCtx, String confirmationMethod,
+            final RelyingPartyConfiguration relyingParty) {
+
+        Subject subject = (Subject) subjectBuilder.buildObject(Subject.DEFAULT_ELEMENT_NAME);
+
+        NameIdentifier nameID = (NameIdentifier) nameIdentifierBuilder.buildObject(NameIdentifier.DEFAULT_ELEMENT_NAME);
+        nameID.setFormat(relyingParty.getDefaultNameIDFormat());
+        String username = loginCtx.getUserID();
+        // XXX: todo: map the username onto an appropriate format
+        nameID.setNameQualifier(username);
+
+        if (subjectConfirmationMethod != null) {
+
+            SubjectConfirmation subjConf = (SubjectConfirmation) subjConfBuilder
+                    .buildObject(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
+
+            ConfirmationMethod m = (ConfirmationMethod) confMethodBuilder
+                    .buildObject(ConfirmationMethod.DEFAULT_ELEMENT_NAME);
+
+            m.setConfirmationMethod(subjectConfirmationMethod);
+            subjConf.getConfirmationMethods().add(m);
+            subject.setSubjectConfirmation(subjConf);
+        }
+
+        return subject;
+    }
+
+    /**
+     * Build a SAML 1 Status element.
+     * 
+     * @param statusCode The status code - see oasis-sstc-saml-core-1.1, section 3.4.3.1.
+     * @param statusMessage The status message, or <code>null</code> if none is to be set.
+     * 
+     * @return The Status object, or <code>null</code> on error.
+     */
+    protected Status buildStatus(String statusCode, String statusMessage) {
+
+        if (statusCode == null || statusCode.equals("")) {
+            return null;
+        }
+
+        Status status = (Status) statusBuilder.buildObject(Status.DEFAULT_ELEMENT_NAME);
+        StatusCode sc = (StatusCode) statusCodeBuilder.buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
+        sc.setValue(statusCode);
+        status.setStatusCode(sc);
+
+        if (statusMessage != null || !(statusMessage.equals(""))) {
+
+            StatusMessage sm = (StatusMessage) statusMessageBuilder.buildObject(StatusMessage.DEFAULT_ELEMENT_NAME);
+            sm.setMessage(statusMessage);
+            status.setStatusMessage(sm);
+        }
+
+        return status;
+    }
+
+    /**
+     * Get an Attribute Statement.
+     * 
+     * @param rpConfig The RelyingPartyConfiguration for the request.
+     * @param subject The Subject of the request.
+     * @param request The ServletRequest.
+     * 
+     * @return An AttributeStatement.
+     * 
+     * @throws ServletException On error.
+     */
+    protected AttributeStatement getAttributeStatement(RelyingPartyConfiguration rpConfig, Subject subject,
+            ServletRequest request) throws ServletException {
+
+        // build a dummy AttributeQuery object for the AA.
+
+        AttributeAuthority aa = new AttributeAuthority();
+        aa.setAttributeResolver(getAttributeResolver());
+        aa.setFilteringEngine(getFilteringEngine());
+        // aa.setSecurityPolicy(getDecoder().getSecurityPolicy()); //
+        // super.getDecoder() will need to change.
+        aa.setRequest(request);
+        aa.setRelyingPartyConfiguration(rpConfig);
+        AttributeStatement statement = null;
+        try {
+            statement = aa.performAttributeQuery(message);
+        } catch (AttributeResolutionException e) {
+            log.error("Error resolving attributes", e);
+            throw new ServletException("Error resolving attributes");
+        } catch (FilteringException e) {
+            log.error("Error filtering attributes", e);
+            throw new ServletException("Error filtering attributes");
+        }
+
+        return statement;
+    }
 }
\ No newline at end of file
index e3ac727..4d6631a 100644 (file)
 
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
+import java.util.List;
+
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
 import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
 import org.opensaml.Configuration;
 import org.opensaml.common.IdentifierGenerator;
 import org.opensaml.common.SAMLObject;
@@ -28,385 +31,236 @@ 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.Assertion;
+import org.opensaml.saml2.core.Audience;
+import org.opensaml.saml2.core.AudienceRestriction;
+import org.opensaml.saml2.core.Conditions;
 import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.Response;
 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.saml2.core.Subject;
+import org.opensaml.xml.XMLObjectBuilder;
 import org.opensaml.xml.XMLObjectBuilderFactory;
 
-import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringEngine;
-import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyManager;
 
 /**
  * Common implementation details for profile handlers.
  */
 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 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;
-       }
+    /** 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;
+
+    /** Relying party configuration. */
+    private RelyingPartyManager relyingPartyManager;
+
+    /** 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.DEFAULT_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 IdentifierGenerator getIdGenerator() {
+        return idGenerator;
+    }
+
+    /**
+     * Returns the relying party manager.
+     * 
+     * @return Returns the relyingPartyManager.
+     */
+    public RelyingPartyManager getRelyingPartyManager() {
+        return relyingPartyManager;
+    }
+
+    /**
+     * Sets the relying party manager.
+     * 
+     * @param m The relyingPartyManager to set.
+     */
+    public void setRelyingPartyManager(RelyingPartyManager m) {
+        relyingPartyManager = m;
+    }
+
+    /**
+     * This decodes the attribute query message from the supplied request.
+     * 
+     * @param decoder <code>MessageDecoder</code>
+     * @param request <code>ServletRequest</code>
+     * @return <code>SAMLObject</code>
+     * @throws BindingException if the request cannot be decoded
+     */
+    public static SAMLObject decodeMessage(MessageDecoder<ServletRequest> decoder, 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 encoder <code>MessageEncoder</code>
+     * @param response <code>SAMLObject</code>
+     * @throws BindingException if the response cannot be encoded
+     */
+    public static void encodeResponse(MessageEncoder<ServletResponse> encoder, 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 Subject 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 f0d4379..2a8a0fa 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 
 import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 
 /**
- * SAML 2.0 Artifact resolution profile handler
+ * SAML 2.0 Artifact resolution profile handler.
  */
 public class ArtifactResolution implements ProfileHandler {
 
     /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
         // TODO Auto-generated method stub
         return false;
     }
index 3395303..82e21e4 100644 (file)
@@ -17,8 +17,6 @@
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 
 import org.apache.log4j.Logger;
 import org.joda.time.DateTime;
@@ -27,16 +25,31 @@ import org.opensaml.common.binding.BindingException;
 import org.opensaml.saml2.core.Advice;
 import org.opensaml.saml2.core.Assertion;
 import org.opensaml.saml2.core.AttributeStatement;
+import org.opensaml.saml2.core.Audience;
+import org.opensaml.saml2.core.AudienceRestriction;
 import org.opensaml.saml2.core.Conditions;
 import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.ProxyRestriction;
 import org.opensaml.saml2.core.Response;
 import org.opensaml.saml2.core.Status;
 import org.opensaml.saml2.core.StatusCode;
 import org.opensaml.saml2.core.Subject;
+import org.opensaml.saml2.encryption.Encrypter;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
 import org.opensaml.xml.encryption.EncryptionException;
+import org.opensaml.xml.security.credential.Credential;
 
-import edu.internet2.middleware.shibboleth.common.attribute.filtering.FilteringException;
-import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolutionException;
+import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
+import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethAttributeRequestContext;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAML2AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.relyingparty.saml2.AttributeQueryConfiguration;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
 
 /**
  * SAML 2.0 Attribute Query profile handler.
@@ -46,8 +59,77 @@ public class AttributeQuery extends AbstractProfileHandler {
     /** Class logger. */
     private static Logger log = Logger.getLogger(AttributeQuery.class);
 
+    /** For building response. */
+    private SAMLObjectBuilder<Response> responseBuilder;
+
+    /** For building status. */
+    private SAMLObjectBuilder<Status> statusBuilder;
+
+    /** For building statuscode. */
+    private SAMLObjectBuilder<StatusCode> statusCodeBuilder;
+
+    /** For building assertion. */
+    private SAMLObjectBuilder<Assertion> assertionBuilder;
+
+    /** For building issuer. */
+    private SAMLObjectBuilder<Issuer> issuerBuilder;
+
+    /** For building subject. */
+    private SAMLObjectBuilder<Subject> subjectBuilder;
+
+    /** For building conditions. */
+    private SAMLObjectBuilder<Conditions> conditionsBuilder;
+
+    /** For building audience restriction. */
+    private SAMLObjectBuilder<AudienceRestriction> audienceRestrictionBuilder;
+
+    /** For building audience. */
+    private SAMLObjectBuilder<Audience> audienceBuilder;
+
+    /** For building advice. */
+    private SAMLObjectBuilder<Advice> adviceBuilder;
+
+    /** Provider id. */
+    private String providerId;
+
+    /** Attribute authority. */
+    private SAML2AttributeAuthority attributeAuthority;
+
+    /** Attribute query configuration. */
+    private AttributeQueryConfiguration config;
+
+    /**
+     * This creates a new attribute query.
+     * 
+     * @param ar <code>AttributeResolver</code>
+     */
+    public AttributeQuery(AttributeResolver<ShibbolethAttributeRequestContext> ar) {
+        // instantiate configuration
+        config = new AttributeQueryConfiguration();
+        providerId = config.getProfileId();
+
+        // instantiate attribute authority
+        attributeAuthority = new ShibbolethSAML2AttributeAuthority(ar);
+
+        // instantiate XML builders
+        responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
+        statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
+        statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
+                StatusCode.DEFAULT_ELEMENT_NAME);
+        assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
+                .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
+        issuerBuilder = (SAMLObjectBuilder<Issuer>) getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
+        subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
+        conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
+                Conditions.DEFAULT_ELEMENT_NAME);
+        audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) getBuilderFactory().getBuilder(
+                AudienceRestriction.DEFAULT_ELEMENT_NAME);
+        audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
+        adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(Advice.DEFAULT_ELEMENT_NAME);
+    }
+
     /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
         if (log.isDebugEnabled()) {
             log.debug("begin processRequest");
         }
@@ -55,47 +137,62 @@ public class AttributeQuery extends AbstractProfileHandler {
         // get message from the decoder
         org.opensaml.saml2.core.AttributeQuery message = null;
         try {
-            message = (org.opensaml.saml2.core.AttributeQuery) decodeMessage(request);
+            message = (org.opensaml.saml2.core.AttributeQuery) decodeMessage(request.getMessageDecoder(), request
+                    .getRequest());
         } catch (BindingException e) {
             log.error("Error decoding attribute query message", e);
             throw new ServletException("Error decoding attribute query message");
         }
 
-        // get attribute statement from attribute authority
-        AttributeAuthority aa = new AttributeAuthority();
-        aa.setAttributeResolver(getAttributeResolver());
-        aa.setFilteringEngine(getFilteringEngine());
-        aa.setRelyingPartyConfiguration(getRelyingPartyConfiguration());
-        aa.setSecurityPolicy(getDecoder().getSecurityPolicy());
-        aa.setRequest(request);
+        // TODO get user data from the session
+        ServiceInformation serviceInformation = null;
+        String principalName = serviceInformation.getSubjectNameID().getSPProvidedID();
+        String authenticationMethod = serviceInformation.getAuthenticationMethod().getAuthenticationMethod();
+
+        // create attribute request for the attribute authority
+        ShibbolethAttributeRequestContext requestContext = null;
+        try {
+            MetadataProvider metadataProvider = getRelyingPartyManager().getMetadataProvider();
+            RelyingPartyConfiguration relyingPartyConfiguration = getRelyingPartyManager()
+                    .getRelyingPartyConfiguration(providerId);
+            requestContext = new ShibbolethAttributeRequestContext(metadataProvider, relyingPartyConfiguration);
+            requestContext.setPrincipalName(principalName);
+            requestContext.setPrincipalAuthenticationMethod(authenticationMethod);
+            requestContext.setRequest(request.getRequest());
+        } catch (MetadataProviderException e) {
+            log.error("Error creating ShibbolethAttributeRequestContext", e);
+            throw new ServletException("Error retrieving metadata", e);
+        }
+
+        // resolve attributes with the attribute authority
         AttributeStatement statement = null;
         try {
-            statement = aa.performAttributeQuery(message);
-        } catch (AttributeResolutionException e) {
+            statement = attributeAuthority.performAttributeQuery(requestContext);
+        } catch (AttributeRequestException e) {
             log.error("Error resolving attributes", e);
-            throw new ServletException("Error resolving attributes");
-        } catch (FilteringException e) {
-            log.error("Error filtering attributes", e);
-            throw new ServletException("Error filtering attributes");
+            throw new ServletException("Error resolving attributes", e);
         }
 
         // construct attribute response
         Response samlResponse = null;
         try {
-            samlResponse = buildResponse(message, request.getRemoteHost(), new DateTime(), statement);
+            ProfileResponseContext profileResponse = new ProfileResponseContext(request, message);
+            profileResponse.setAttributeStatement(statement);
+            samlResponse = buildResponse(profileResponse);
         } catch (EncryptionException e) {
             log.error("Error encrypting SAML response", e);
-            throw new ServletException("Error encrypting SAML response");
+            throw new ServletException("Error encrypting SAML response", e);
         }
         if (log.isDebugEnabled()) {
             log.debug("built saml2 response: " + samlResponse);
         }
 
+        // encode response
         try {
-            encodeResponse(samlResponse);
+            encodeResponse(response.getMessageEncoder(), samlResponse);
         } catch (BindingException e) {
             log.error("Error encoding attribute query response", e);
-            throw new ServletException("Error encoding attribute query response");
+            throw new ServletException("Error encoding attribute query response", e);
         }
 
         return true;
@@ -104,63 +201,66 @@ public class AttributeQuery extends AbstractProfileHandler {
     /**
      * This builds the response for this SAML request.
      * 
-     * @param message <code>AttributeQuery</code>
-     * @param dest <code>String</code>
-     * @param issueInstant <code>DateTime</code>
-     * @param statement <code>AttributeStatement</code> of attributes
+     * @param responseContext <code>ProfileResponseContext</code>
      * @return <code>Response</code>
      * @throws EncryptionException if an error occurs attempting to encrypt data
      */
-    public Response buildResponse(org.opensaml.saml2.core.AttributeQuery message, String dest, DateTime issueInstant,
-            AttributeStatement statement) throws EncryptionException {
-        SAMLObjectBuilder<Response> responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(
-                Response.DEFAULT_ELEMENT_NAME);
+    private Response buildResponse(ProfileResponseContext responseContext) throws EncryptionException {
         /*
          * required: samlp:Status, ID, Version, IssueInstant
          */
         Response response = responseBuilder.buildObject();
         response.setVersion(SAML_VERSION);
         response.setID(getIdGenerator().generateIdentifier());
-        response.setInResponseTo(getDecoder().getSecurityPolicy().getIssuer().toString());
-        response.setIssueInstant(issueInstant);
-        response.setDestination(dest);
+        response.setInResponseTo(responseContext.getRequest().getMessageDecoder().getSecurityPolicy().getIssuer()
+                .toString());
+        response.setIssueInstant(responseContext.getIssueInstant());
+        response.setDestination(responseContext.getRequest().getRequest().getRemoteHost());
 
         response.setIssuer(buildIssuer());
-        // TODO set consent
+
+        // TODO get consent configuration
         /*
          * if (consent != null) { response.setConsent(consent); }
          */
-        // TODO set extensions
+
+        // TODO get extension configuration
         /*
          * if (extensions != null) { response.setExtensions(extensions); }
          */
 
-        response.setStatus(buildStatus());
-        if (getRelyingPartyConfiguration().encryptAssertion()) {
-            response.getEncryptedAssertions().add(
-                    getEncrypter().encrypt(buildAssertion(message.getSubject(), issueInstant, statement)));
+        if (config.getSignAssertions()) {
+            // TODO sign assertion: Credential credential = config.getSigningCredential();
+            if (config.getEncryptAssertion()) {
+                // TODO load encryption parameters
+                Encrypter encrypter = null;
+                response.getEncryptedAssertions().add(encrypter.encrypt(buildAssertion(responseContext)));
+            } else {
+                response.getAssertions().add(buildAssertion(responseContext));
+            }
         } else {
-            response.getAssertions().add(buildAssertion(message.getSubject(), issueInstant, statement));
+            if (config.getEncryptAssertion()) {
+                // TODO load encryption parameters
+                Encrypter encrypter = null;
+                response.getEncryptedAssertions().add(encrypter.encrypt(buildAssertion(responseContext)));
+            } else {
+                response.getAssertions().add(buildAssertion(responseContext));
+            }
         }
+        response.setStatus(buildStatus(StatusCode.SUCCESS_URI));
         return response;
     }
 
     /**
      * This builds the status response for this SAML request.
      * 
+     * @param statusCodeUri <code>String</code> to set
      * @return <code>Status</code>
      */
-    private Status buildStatus() {
-        // build status
-        SAMLObjectBuilder<Status> statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(
-                Status.DEFAULT_ELEMENT_NAME);
+    private Status buildStatus(String statusCodeUri) {
         Status status = statusBuilder.buildObject();
-
-        // build status code
-        SAMLObjectBuilder<StatusCode> statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory()
-                .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
         StatusCode statusCode = statusCodeBuilder.buildObject();
-        statusCode.setValue(StatusCode.SUCCESS_URI);
+        statusCode.setValue(statusCodeUri);
         status.setStatusCode(statusCode);
         return status;
     }
@@ -168,34 +268,28 @@ public class AttributeQuery extends AbstractProfileHandler {
     /**
      * This builds the assertion for this SAML request.
      * 
-     * @param messageSubject <code>Subject</code>
-     * @param issueInstant <code>DateTime</code>
-     * @param statement <code>AttributeStatement</code> of attributes
+     * @param responseContext <code>ProfileResponseContext</code>
      * @return <code>Assertion</code>
      * @throws EncryptionException if an error occurs attempting to encrypt data
      */
-    private Assertion buildAssertion(Subject messageSubject, DateTime issueInstant, AttributeStatement statement)
-            throws EncryptionException {
-        // build assertions
-        SAMLObjectBuilder<Assertion> assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(
-                Assertion.DEFAULT_ELEMENT_NAME);
+    private Assertion buildAssertion(ProfileResponseContext responseContext) throws EncryptionException {
         /*
          * required: saml:Issuer, ID, Version, IssueInstant
          */
         Assertion assertion = assertionBuilder.buildObject();
         assertion.setID(getIdGenerator().generateIdentifier());
-        assertion.setIssueInstant(issueInstant);
+        assertion.setIssueInstant(responseContext.getIssueInstant());
         assertion.setVersion(SAML_VERSION);
         assertion.setIssuer(buildIssuer());
 
         // build subject
-        assertion.setSubject(buildSubject(messageSubject));
+        assertion.setSubject(buildSubject(responseContext.getMessage().getSubject()));
         // build conditions
-        assertion.setConditions(buildConditions(issueInstant));
+        assertion.setConditions(buildConditions(responseContext.getIssueInstant()));
         // build advice
         assertion.setAdvice(buildAdvice());
         // add attribute statement
-        assertion.getAttributeStatements().add(statement);
+        assertion.getAttributeStatements().add(responseContext.getAttributeStatement());
         return assertion;
     }
 
@@ -205,11 +299,10 @@ public class AttributeQuery extends AbstractProfileHandler {
      * @return <code>Issuer</code>
      */
     private Issuer buildIssuer() {
-        // build status
-        SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) getBuilderFactory().getBuilder(
-                Issuer.DEFAULT_ELEMENT_NAME);
+        RelyingPartyConfiguration relyingPartyConfiguration = getRelyingPartyManager().getRelyingPartyConfiguration(
+                providerId);
         Issuer issuer = issuerBuilder.buildObject();
-        issuer.setValue(getRelyingPartyConfiguration().getProviderID());
+        issuer.setValue(relyingPartyConfiguration.getProviderID());
         return issuer;
     }
 
@@ -221,12 +314,11 @@ public class AttributeQuery extends AbstractProfileHandler {
      * @throws EncryptionException if encryption of the name id fails
      */
     private Subject buildSubject(Subject messageSubject) throws EncryptionException {
-        // build subject
-        SAMLObjectBuilder<Subject> subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(
-                Subject.DEFAULT_ELEMENT_NAME);
         Subject subject = subjectBuilder.buildObject();
-        if (getRelyingPartyConfiguration().encryptNameID()) {
-            subject.setEncryptedID(getEncrypter().encrypt(messageSubject.getNameID()));
+        if (config.getEncryptNameID()) {
+            // TODO load encryption parameters
+            Encrypter encrypter = null;
+            subject.setEncryptedID(encrypter.encrypt(messageSubject.getNameID()));
         } else {
             subject.setNameID(messageSubject.getNameID());
             // TODO when is subject.setBaseID(newBaseID) called, if ever?
@@ -241,13 +333,30 @@ public class AttributeQuery extends AbstractProfileHandler {
      * @return <code>Conditions</code>
      */
     private Conditions buildConditions(DateTime issueInstant) {
-        SAMLObjectBuilder<Conditions> conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
-                .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
         Conditions conditions = conditionsBuilder.buildObject();
         conditions.setNotBefore(issueInstant);
-        // TODO conditions.setNotOnOrAfter();
+        conditions.setNotOnOrAfter(issueInstant.plus(config.getAssertionLifetime()));
+
+        // add audience restrictions
+        AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject();
+        for (String s : config.getAssertionAudiences()) {
+            Audience audience = audienceBuilder.buildObject();
+            audience.setAudienceURI(s);
+            audienceRestriction.getAudiences().add(audience);
+        }
+        conditions.getAudienceRestrictions().add(audienceRestriction);
+
+        // add proxy restrictions
+        ProxyRestriction proxyRestriction = conditions.getProxyRestriction();
+        for (String s : config.getProxyAudiences()) {
+            Audience audience = audienceBuilder.buildObject();
+            audience.setAudienceURI(s);
+            proxyRestriction.getAudiences().add(audience);
+        }
+        proxyRestriction.setProxyCount(new Integer(config.getProxyCount()));
+
         // TODO add additional conditions : conditions.getConditions().add(Condition);
-        // TODO what about AudienceRestriction, OneTimeUse, ProxyRestriction?
+        // TODO what about OneTimeUse?
         return conditions;
     }
 
@@ -257,9 +366,8 @@ public class AttributeQuery extends AbstractProfileHandler {
      * @return <code>Advice</code>
      */
     private Advice buildAdvice() {
-        SAMLObjectBuilder<Advice> adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(
-                Advice.DEFAULT_ELEMENT_NAME);
         Advice advice = adviceBuilder.buildObject();
+        // TODO set advice
         // advice.getAssertionIDReferences().add();
         // advice.getAssertionURIReferences().add();
         // advice.getAssertions().add();
index d075ead..d5188fd 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -25,807 +26,693 @@ import java.util.List;
 
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyManager;
-import edu.internet2.middleware.shibboleth.common.relyingparty.saml2.SSOConfiguration;
-import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationManager;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
-
 import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
 import org.opensaml.Configuration;
-import org.opensaml.DefaultBootstrap;
+import org.opensaml.common.binding.ArtifactMap;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.common.binding.SAMLArtifactFactory;
 import org.opensaml.saml2.core.Assertion;
+import org.opensaml.saml2.core.Audience;
 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.AuthnStatement;
 import org.opensaml.saml2.core.GetComplete;
 import org.opensaml.saml2.core.IDPEntry;
 import org.opensaml.saml2.core.IDPList;
-import org.opensaml.saml2.core.LogoutRequest;
+import org.opensaml.saml2.core.Issuer;
 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.StatusCode;
 import org.opensaml.saml2.core.Subject;
 import org.opensaml.saml2.core.SubjectConfirmation;
 import org.opensaml.saml2.metadata.AssertionConsumerService;
-import org.opensaml.saml2.metadata.MetadataProvider;
-import org.opensaml.saml2.metadata.provider.ProviderException;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.provider.MetadataProvider;
+import org.opensaml.saml2.metadata.provider.MetadataProviderException;
 import org.opensaml.xml.ConfigurationException;
+import org.opensaml.xml.XMLObjectBuilder;
 import org.opensaml.xml.io.Unmarshaller;
 import org.opensaml.xml.io.UnmarshallingException;
 import org.opensaml.xml.parse.ParserPool;
-import org.opensaml.xml.XMLObjectBuilder;
 import org.opensaml.xml.parse.XMLParserException;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import org.xml.sax.InputSource;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyManager;
+import edu.internet2.middleware.shibboleth.common.relyingparty.saml2.SSOConfiguration;
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationManager;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
 
 /**
  * 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 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);
-       }
-
-       /**
-        * 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;
-
-               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;
-       }
-
-       /**
-        * 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 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);
-       }
-
-       /**
-        * 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.
-        * 
-        * @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.
-       }
-
-       /**
-        * 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;
-       }
-
-       /**
-        * 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);
-       }
-
-       /**
-        * 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);
-       }
-
-       /**
-        * 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 {
-                       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) {
-                               try {
-                                       istream.close();
-                               } catch (IOException ex) {
-                                       // pass
-                               }
-                       }
-               }
-
-               return idpList;
-       }
+    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);
+    }
+
+    /**
+     * 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(ProfileRequest request, ProfileResponse response) throws ServletException {
+
+        // Only http servlets are supported for now.
+        if (!(request.getRequest() instanceof HttpServletRequest)) {
+            log.error("Received a non-HTTP request from " + request.getRequest().getRemoteHost());
+            throw new ServletException("Received a non-HTTP request");
+        }
+
+        HttpServletRequest httpReq = (HttpServletRequest) request.getRequest();
+        HttpServletResponse httpResp = (HttpServletResponse) response.getResponse();
+        HttpSession httpSession = httpReq.getSession();
+
+        AuthnRequest authnRequest;
+        try {
+            // this will need to change
+            authnRequest = (org.opensaml.saml2.core.AuthnRequest) decodeMessage(request.getMessageDecoder(), request
+                    .getRequest());
+            // 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;
+    }
+
+    /**
+     * 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 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);
+    }
+
+    /**
+     * 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.
+     * 
+     * @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.
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * 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 {
+            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) {
+                try {
+                    istream.close();
+                } catch (IOException ex) {
+                    // pass
+                }
+            }
+        }
+
+        return idpList;
+    }
 }
index 61b5556..2320ee9 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
 
 import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 
 import edu.internet2.middleware.shibboleth.common.profile.ProfileHandler;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 
 /**
- * SAML 2.0 Logout Request profile handler
+ * SAML 2.0 Logout Request profile handler.
  */
 public class LogoutRequest implements ProfileHandler {
 
     /** {@inheritDoc} */
-    public boolean processRequest(ServletRequest request, ServletResponse response) throws ServletException {
+    public boolean processRequest(ProfileRequest request, ProfileResponse response) throws ServletException {
         // TODO Auto-generated method stub
         return false;
     }
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/saml2/ProfileResponseContext.java b/src/edu/internet2/middleware/shibboleth/idp/profile/saml2/ProfileResponseContext.java
new file mode 100644 (file)
index 0000000..b43b181
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package edu.internet2.middleware.shibboleth.idp.profile.saml2;
+
+import org.joda.time.DateTime;
+import org.opensaml.saml2.core.SubjectQuery;
+import org.opensaml.saml2.core.AttributeStatement;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+
+/**
+ * Contains contextual information used in processing profile responses.
+ */
+public class ProfileResponseContext {
+
+    /** Profile request. */
+    private ProfileRequest request;
+
+    /** Profile request message. */
+    private SubjectQuery message;
+
+    /** Issue instant for the response. */
+    private DateTime issueInstant;
+
+    /** Response statement. */
+    private AttributeStatement attributeStatement;
+
+    /**
+     * Constructor.
+     * 
+     * @param r serlvet request
+     * @param m decoded profile request message
+     */
+
+    public ProfileResponseContext(ProfileRequest r, SubjectQuery m) {
+        request = r;
+        message = m;
+        issueInstant = new DateTime();
+    }
+
+    /**
+     * Gets the initiating profile request.
+     * 
+     * @return profile request
+     */
+    public ProfileRequest getRequest() {
+        return request;
+    }
+
+    /**
+     * Gets the decoded profile request message.
+     * 
+     * @return profile request message
+     */
+    public SubjectQuery getMessage() {
+        return message;
+    }
+
+    /**
+     * Gets the issue instant for the response.
+     * 
+     * @return issue instant
+     */
+    public DateTime getIssueInstant() {
+        return issueInstant;
+    }
+
+    /**
+     * Sets a attribute statement associated with this response.
+     * 
+     * @param s to sets
+     */
+    public void setAttributeStatement(AttributeStatement s) {
+        attributeStatement = s;
+    }
+
+    /**
+     * Gets the statement associated with this response.
+     * 
+     * @return response statement
+     */
+    public AttributeStatement getAttributeStatement() {
+        return attributeStatement;
+    }
+}