Reworked Shib SSO profile handler
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 9 Jun 2007 22:45:14 +0000 (22:45 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Sat, 9 Jun 2007 22:45:14 +0000 (22:45 +0000)
Minor code/comment cleanups

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

src/edu/internet2/middleware/shibboleth/idp/authn/LoginContext.java
src/edu/internet2/middleware/shibboleth/idp/authn/ShibbolethSSOLoginContext.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/AbstractSAML1ProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/AttributeQueryProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSO.java [deleted file]
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSOProfileHandler.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AbstractSAML2ProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AttributeQueryProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/SSOProfileHandler.java

index 3aef09c..c3b9670 100644 (file)
@@ -48,7 +48,7 @@ public class LoginContext implements Serializable {
 
     /** the key in a HttpSession where login contexts are stored. */
     public static final String LOGIN_CONTEXT_KEY = "shib2.logincontext";
-    
+
     /** Serial version UID. */
     private static final long serialVersionUID = 4268661186941572372L;
 
@@ -149,19 +149,19 @@ public class LoginContext implements Serializable {
     /**
      * Sets if authentication must be forced.
      * 
-     * @param forceAuth if the authentication manager must reauth the user.
+     * @param force if the authentication manager must reauth the user.
      */
-    public void setForceAuth(boolean forceAuth) {
-        this.forceAuth = forceAuth;
+    public void setForceAuth(boolean force) {
+        forceAuth = force;
     }
 
     /**
      * Sets if authentication must be passive.
      * 
-     * @param passiveAuth if the authentication manager must not interact with the users UI.
+     * @param passicve if the authentication manager must not interact with the users UI.
      */
-    public void setPassiveAuth(boolean passiveAuth) {
-        this.passiveAuth = passiveAuth;
+    public void setPassiveAuth(boolean passicve) {
+        passiveAuth = passicve;
     }
 
     /**
@@ -271,10 +271,10 @@ public class LoginContext implements Serializable {
     /**
      * Sets the ProfileHandler URL.
      * 
-     * @param profileHandlerURL The URL of the profile handler that invoked the AuthenticationManager/
+     * @param url The URL of the profile handler that invoked the AuthenticationManager/
      */
-    public void setProfileHandlerURL(String profileHandlerURL) {
-        this.profileHandlerURL = profileHandlerURL;
+    public void setProfileHandlerURL(String url) {
+        profileHandlerURL = url;
     }
 
     /**
@@ -289,10 +289,10 @@ public class LoginContext implements Serializable {
     /**
      * Sets the AuthenticationManager's URL.
      * 
-     * @param authnManagerURL the URL of the AuthenticationManager.
+     * @param url the URL of the AuthenticationManager.
      */
-    public void setAuthenticationManagerURL(String authnManagerURL) {
-        this.authnManagerURL = authnManagerURL;
+    public void setAuthenticationManagerURL(String url) {
+        authnManagerURL = url;
     }
 
     /**
@@ -307,10 +307,10 @@ public class LoginContext implements Serializable {
     /**
      * Sets the authentication instant.
      * 
-     * @param authnInstant The instant of authentication.
+     * @param instant The instant of authentication.
      */
-    public void setAuthenticationInstant(final DateTime authnInstant) {
-        this.authnInstant = authnInstant;
+    public void setAuthenticationInstant(final DateTime instant) {
+        authnInstant = instant;
     }
 
     /**
@@ -325,10 +325,10 @@ public class LoginContext implements Serializable {
     /**
      * Sets the duration of authentication.
      * 
-     * @param authnDuration The duration of authentication.
+     * @param duration The duration of authentication.
      */
-    public void setAuthenticationDuration(long authnDuration) {
-        this.authnDuration = authnDuration;
+    public void setAuthenticationDuration(long duration) {
+        authnDuration = duration;
     }
 
     /**
@@ -343,28 +343,28 @@ public class LoginContext implements Serializable {
     /**
      * Sets the method used to authenticate the user.
      * 
-     * @param authnMethod The method used to authenticate the user.
+     * @param method The method used to authenticate the user.
      */
-    public void setAuthenticationMethod(String authnMethod) {
-        this.authnMethod = authnMethod;
+    public void setAuthenticationMethod(String method) {
+        authnMethod = method;
     }
 
     /**
-     * Gets the {@link Session} ID
+     * Gets the {@link Session} ID.
      * 
-     * @return the Session id.
+     * @return the Session id
      */
     public String getSessionID() {
         return sessionID;
     }
 
     /**
-     * Sets the {@link Session} ID
+     * Sets the {@link Session} ID.
      * 
-     * @param sessionID the Session ID
+     * @param id the Session ID
      */
-    public void setSessionID(String sessionID) {
-        this.sessionID = sessionID;
+    public void setSessionID(String id) {
+        sessionID = id;
     }
 
     /**
@@ -376,4 +376,4 @@ public class LoginContext implements Serializable {
     public List<String> getRequestedAuthenticationMethods() {
         return new ArrayList<String>();
     }
-}
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/ShibbolethSSOLoginContext.java b/src/edu/internet2/middleware/shibboleth/idp/authn/ShibbolethSSOLoginContext.java
new file mode 100644 (file)
index 0000000..659c318
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.authn;
+
+/** Shibboleth SSO aware extension to {@link LoginContext}. */
+public class ShibbolethSSOLoginContext extends LoginContext {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = -8388394528549536613L;
+
+    /** Service provider assertion consumer service URL. */
+    private String spAssertionConsumerService;
+
+    /** Service provider target URL. */
+    private String spTarget;
+
+    /** Constructor. */
+    public ShibbolethSSOLoginContext() {
+        super(false, false);
+    }
+
+    /**
+     * Gets the service provider assertion consumer service URL.
+     * 
+     * @return service provider assertion consumer service URL
+     */
+    public String getSpAssertionConsumerService() {
+        return spAssertionConsumerService;
+    }
+
+    /**
+     * Sets the service provider assertion consumer service URL.
+     * 
+     * @param url service provider assertion consumer service URL
+     */
+    public void setSpAssertionConsumerService(String url) {
+        spAssertionConsumerService = url;
+    }
+
+    /**
+     * Gets the service provider target URL.
+     * 
+     * @return service provider target URL
+     */
+    public String getSpTarget() {
+        return spTarget;
+    }
+
+    /**
+     * Sets the service provider target URL.
+     * 
+     * @param url service provider target URL
+     */
+    public void setSpTarget(String url) {
+        spTarget = url;
+    }
+}
\ No newline at end of file
index 57fee58..1974f1b 100644 (file)
@@ -31,7 +31,10 @@ import org.opensaml.common.SAMLObjectBuilder;
 import org.opensaml.common.SAMLVersion;
 import org.opensaml.common.impl.SAMLObjectContentReference;
 import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.log.Level;
 import org.opensaml.saml1.core.Assertion;
+import org.opensaml.saml1.core.AttributeQuery;
+import org.opensaml.saml1.core.AttributeStatement;
 import org.opensaml.saml1.core.Audience;
 import org.opensaml.saml1.core.AudienceRestrictionCondition;
 import org.opensaml.saml1.core.Conditions;
@@ -64,15 +67,18 @@ import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestExce
 import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
 import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncoder;
 import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncodingException;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
+import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAMLAttributeRequestContext;
+import edu.internet2.middleware.shibboleth.common.log.AuditLogEntry;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
 
-/**
- * Common implementation details for profile handlers.
- */
+/** Common implementation details for profile handlers. */
 public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
 
     /** SAML Version for this profile handler. */
@@ -266,10 +272,9 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
      * @return the built response
      * 
      * @throws ProfileException thrown if there is a problem creating the SAML response
-     * @throws AttributeRequestException thrown if there is a problem resolving attributes
      */
     protected Response buildResponse(SAML1ProfileRequestContext requestContext, List<Statement> statements)
-            throws ProfileException, AttributeRequestException {
+            throws ProfileException {
 
         DateTime issueInstant = new DateTime();
 
@@ -421,10 +426,13 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
                     }
                 }
             } catch (AttributeEncodingException e) {
+                requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null,
+                        "Unable to construct NameIdentifier"));
                 throw new ProfileException("Unable to encode NameIdentifier attribute", e);
             }
         }
 
+        requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Unable to construct NameID"));
         throw new ProfileException("No principal attributes support NameIdentifier construction");
     }
 
@@ -460,6 +468,7 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
             return nameFormats;
 
         } catch (MetadataProviderException e) {
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Unable to lookup metadata"));
             throw new ProfileException("Unable to determine lookup entity metadata", e);
         }
     }
@@ -497,21 +506,16 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
     /**
      * Constructs an SAML response message carrying a request error.
      * 
-     * @param requestContext current request context
-     * @param topLevelCode top-level status code
-     * @param secondLevelCode second-level status code
-     * @param failureMessage An optional second-level failure message
+     * @param requestContext current request context containing the failure status
      * 
      * @return the constructed error response
      */
-    protected Response buildErrorResponse(SAML1ProfileRequestContext requestContext, String topLevelCode,
-            String secondLevelCode, String failureMessage) {
+    protected Response buildErrorResponse(SAML1ProfileRequestContext requestContext) {
         Response samlResponse = getResponseBuilder().buildObject();
         samlResponse.setIssueInstant(new DateTime());
         populateStatusResponse(requestContext, samlResponse);
 
-        Status status = buildStatus(topLevelCode, secondLevelCode, failureMessage);
-        samlResponse.setStatus(status);
+        samlResponse.setStatus(requestContext.getFailureStatus());
 
         return samlResponse;
     }
@@ -564,6 +568,128 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
     }
 
     /**
+     * Executes a query for attributes and builds a SAML attribute statement from the results.
+     * 
+     * @param requestContext current request context
+     * @param subjectConfMethod subject confirmation method
+     * 
+     * @return attribute statement resulting from the query
+     * 
+     * @throws ProfileException thrown if there is a problem making the query
+     */
+    protected AttributeStatement buildAttributeStatement(SAML1ProfileRequestContext requestContext, String subjectConfMethod)
+            throws ProfileException {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Creating attribute statement in response to SAML request from relying party "
+                    + requestContext.getRelyingPartyId());
+        }
+
+        AbstractSAML1ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+        SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
+
+        try {
+            if (log.isDebugEnabled()) {
+                log.debug("Resolving attributes for principal " + requestContext.getPrincipalName()
+                        + " of SAML request from relying party " + requestContext.getRelyingPartyId());
+            }
+            Map<String, BaseAttribute> principalAttributes = attributeAuthority
+                    .getAttributes(buildAttributeRequestContext(requestContext));
+
+            requestContext.setPrincipalAttributes(principalAttributes);
+
+            AttributeStatement statment;
+            if (requestContext.getSamlRequest() instanceof AttributeQuery) {
+                statment = attributeAuthority.buildAttributeStatement((AttributeQuery) requestContext.getSamlRequest(),
+                        principalAttributes.values());
+            } else {
+                statment = attributeAuthority.buildAttributeStatement(null, principalAttributes.values());
+            }
+
+            Subject statementSubject = buildSubject(requestContext, subjectConfMethod);
+            statment.setSubject(statementSubject);
+
+            return statment;
+        } catch (AttributeRequestException e) {
+            log.error("Error resolving attributes for SAML request from relying party "
+                    + requestContext.getRelyingPartyId(), e);
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Error resolving attributes"));
+            throw new ProfileException("Error resolving attributes for SAML request from relying party "
+                    + requestContext.getRelyingPartyId(), e);
+        }
+    }
+
+    /**
+     * Resolves the principal name of the subject of the request.
+     * 
+     * @param requestContext current request context
+     * 
+     * @throws ProfileException thrown if the principal name can not be resolved
+     */
+    protected void resolvePrincipal(SAML1ProfileRequestContext requestContext) throws ProfileException {
+        AbstractSAML1ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
+        SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
+
+        if (log.isDebugEnabled()) {
+            log.debug("Resolving principal name for subject of SAML request from relying party "
+                    + requestContext.getRelyingPartyId());
+        }
+
+        try {
+            String principal = attributeAuthority.getPrincipal(buildAttributeRequestContext(requestContext));
+            requestContext.setPrincipalName(principal);
+        } catch (AttributeRequestException e) {
+            log.error("Error resolving attributes for SAML request from relying party "
+                    + requestContext.getRelyingPartyId(), e);
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, StatusCode.REQUEST_DENIED,
+                    "Error resolving principal"));
+            throw new ProfileException("Error resolving attributes for SAML request from relying party "
+                    + requestContext.getRelyingPartyId(), e);
+        }
+    }
+
+    /**
+     * Creates an attribute query context from the current profile request context.
+     * 
+     * @param requestContext current profile request
+     * 
+     * @return created query context
+     */
+    protected ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> buildAttributeRequestContext(
+            SAML1ProfileRequestContext requestContext) {
+
+        ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> queryContext;
+
+        if (requestContext.getSamlRequest() instanceof AttributeQuery) {
+            queryContext = new ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery>(
+                    getMetadataProvider(), requestContext.getRelyingPartyConfiguration(),
+                    (AttributeQuery) requestContext.getSamlRequest());
+        } else {
+            queryContext = new ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery>(
+                    getMetadataProvider(), requestContext.getRelyingPartyConfiguration());
+        }
+
+        queryContext.setAttributeRequester(requestContext.getAssertingPartyId());
+        queryContext.setPrincipalName(requestContext.getPrincipalName());
+        queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
+        queryContext.setRequest(requestContext.getProfileRequest());
+
+        Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
+        if (userSession != null) {
+            queryContext.setUserSession(userSession);
+            ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
+            if (serviceInfo != null) {
+                String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
+
+                requestContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+                queryContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
+            }
+        }
+
+        return queryContext;
+    }
+
+    /**
      * Signs the given assertion if either the current profile configuration or the relying party configuration contains
      * signing credentials.
      * 
@@ -639,6 +765,25 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
     }
 
     /**
+     * Writes an aduit log entry indicating the successful response to the attribute request.
+     * 
+     * @param context current request context
+     */
+    protected void writeAuditLogEntry(SAML1ProfileRequestContext context) {
+        AuditLogEntry auditLogEntry = new AuditLogEntry();
+        auditLogEntry.setMessageProfile(getProfileId());
+        auditLogEntry.setPrincipalAuthenticationMethod(context.getPrincipalAuthenticationMethod());
+        auditLogEntry.setPrincipalName(context.getPrincipalName());
+        auditLogEntry.setAssertingPartyId(context.getAssertingPartyId());
+        auditLogEntry.setRelyingPartyId(context.getRelyingPartyId());
+        auditLogEntry.setRequestBinding(context.getMessageDecoder().getBindingURI());
+        auditLogEntry.setRequestId(null);
+        auditLogEntry.setResponseBinding(context.getMessageEncoder().getBindingURI());
+        auditLogEntry.setResponseId(context.getSamlResponse().getID());
+        getAduitLog().log(Level.CRITICAL, auditLogEntry);
+    }
+
+    /**
      * Contextual object used to accumlate information as profile requests are being processed.
      * 
      * @param <RequestType> type of SAML 1 request
@@ -660,6 +805,9 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
         /** The NameIdentifier of the subject of this request. */
         private NameIdentifier subjectNameIdentifier;
 
+        /** The request failure status. */
+        private Status failureStatus;
+
         /**
          * Constructor.
          * 
@@ -742,5 +890,23 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
         public void setSamlResponse(ResponseType response) {
             samlResponse = response;
         }
+
+        /**
+         * Gets the status reflecting a request failure.
+         * 
+         * @return status reflecting a request failure
+         */
+        public Status getFailureStatus() {
+            return failureStatus;
+        }
+
+        /**
+         * Sets the status reflecting a request failure.
+         * 
+         * @param status status reflecting a request failure
+         */
+        public void setFailureStatus(Status status) {
+            failureStatus = status;
+        }
     }
 }
\ No newline at end of file
index 9626fe2..e3cacc8 100644 (file)
@@ -17,7 +17,6 @@
 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
 
 import java.util.ArrayList;
-import java.util.Map;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -30,27 +29,18 @@ import org.opensaml.common.binding.security.SAMLSecurityPolicy;
 import org.opensaml.saml1.binding.decoding.HTTPSOAP11Decoder;
 import org.opensaml.saml1.binding.encoding.HTTPSOAP11Encoder;
 import org.opensaml.saml1.core.AttributeQuery;
-import org.opensaml.saml1.core.AttributeStatement;
-import org.opensaml.saml1.core.NameIdentifier;
 import org.opensaml.saml1.core.Response;
 import org.opensaml.saml1.core.Statement;
 import org.opensaml.saml1.core.StatusCode;
-import org.opensaml.saml1.core.Subject;
 import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
 import org.opensaml.saml2.metadata.SPSSODescriptor;
 import org.opensaml.ws.security.SecurityPolicyException;
 
-import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
-import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
-import edu.internet2.middleware.shibboleth.common.attribute.provider.SAML1AttributeAuthority;
-import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAMLAttributeRequestContext;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AttributeQueryConfiguration;
-import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
-import edu.internet2.middleware.shibboleth.idp.session.Session;
 
 /**
  * SAML 1 Attribute Query profile handler.
@@ -75,18 +65,14 @@ public class AttributeQueryProfileHandler extends AbstractSAML1ProfileHandler {
         try {
             decodeRequest(requestContext);
 
+            resolvePrincipal(requestContext);
+
             ArrayList<Statement> statements = new ArrayList<Statement>();
-            statements.add(buildAttributeStatement(requestContext));
+            statements.add(buildAttributeStatement(requestContext, "urn:oasis:names:tc:SAML:1.0:cm:sender-vouches"));
 
             samlResponse = buildResponse(requestContext, statements);
-        } catch (SecurityPolicyException e) {
-            samlResponse = buildErrorResponse(requestContext, StatusCode.REQUESTER, StatusCode.REQUEST_DENIED, e
-                    .getMessage());
-        } catch (AttributeRequestException e) {
-            samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER, null, e.getMessage());
         } catch (ProfileException e) {
-            samlResponse = buildErrorResponse(requestContext, StatusCode.RESPONDER, StatusCode.REQUEST_DENIED, e
-                    .getMessage());
+            samlResponse = buildErrorResponse(requestContext);
         }
     }
 
@@ -96,10 +82,8 @@ public class AttributeQueryProfileHandler extends AbstractSAML1ProfileHandler {
      * @param requestContext request context contianing the request to decode
      * 
      * @throws ProfileException throw if there is a problem decoding the request
-     * @throws SecurityPolicyException thrown if the message was decoded properly but did not meet the necessary
-     *             security policy requirements
      */
-    protected void decodeRequest(AttributeQueryContext requestContext) throws ProfileException, SecurityPolicyException {
+    protected void decodeRequest(AttributeQueryContext requestContext) throws ProfileException {
         if (log.isDebugEnabled()) {
             log.debug("Decoding incomming request");
         }
@@ -121,7 +105,13 @@ public class AttributeQueryProfileHandler extends AbstractSAML1ProfileHandler {
             }
         } catch (BindingException e) {
             log.error("Error decoding attribute query message", e);
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "Error decoding message"));
             throw new ProfileException("Error decoding attribute query message");
+        } catch (SecurityPolicyException e) {
+            log.error("Message did not meet security policy requirements", e);
+            requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, StatusCode.REQUEST_DENIED,
+                    "Message did not meet security policy requirements"));
+            throw new ProfileException("Message did not meet security policy requirements", e);
         } finally {
             // Set as much information as can be retrieved from the decoded message
             SAMLSecurityPolicy securityPolicy = requestContext.getMessageDecoder().getSecurityPolicy();
@@ -144,99 +134,6 @@ public class AttributeQueryProfileHandler extends AbstractSAML1ProfileHandler {
     }
 
     /**
-     * Executes a query for attributes and builds a SAML attribute statement from the results.
-     * 
-     * @param requestContext current request context
-     * 
-     * @return attribute statement resulting from the query
-     * 
-     * @throws ProfileException thrown if there is a problem making the query
-     * @throws AttributeRequestException thrown if there is a problem resolving attributes
-     */
-    protected AttributeStatement buildAttributeStatement(AttributeQueryContext requestContext) throws ProfileException,
-            AttributeRequestException {
-
-        if (log.isDebugEnabled()) {
-            log.debug("Creating attribute statement in response to SAML request  from relying party "
-                    + requestContext.getRelyingPartyId());
-        }
-
-        try {
-            AttributeQueryConfiguration profileConfiguration = requestContext.getProfileConfiguration();
-            if (profileConfiguration == null) {
-                log.error("No SAML 1 attribute query profile configuration is defined for relying party: "
-                        + requestContext.getRelyingPartyId());
-                throw new AttributeRequestException("SAML 1 attribute query is not configured for this relying party");
-            }
-
-            SAML1AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
-
-            ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> attributeRequestContext = buildAttributeRequestContext(requestContext);
-
-            if (log.isDebugEnabled()) {
-                log.debug("Resolving principal name for subject of SAML request from relying party "
-                        + requestContext.getRelyingPartyId());
-            }
-            String principal = attributeAuthority.getPrincipal(attributeRequestContext);
-            requestContext.setPrincipalName(principal);
-
-            if (log.isDebugEnabled()) {
-                log.debug("Resolving attributes for principal " + principal + " of SAML request from relying party "
-                        + requestContext.getRelyingPartyId());
-            }
-            Map<String, BaseAttribute> principalAttributes = attributeAuthority
-                    .getAttributes(buildAttributeRequestContext(requestContext));
-
-            requestContext.setPrincipalAttributes(principalAttributes);
-
-            AttributeStatement statment = attributeAuthority.buildAttributeStatement(requestContext.getSamlRequest(),
-                    principalAttributes.values());
-
-            Subject statementSubject = buildSubject(requestContext, "urn:oasis:names:tc:SAML:1.0:cm:sender-vouches");
-            statment.setSubject(statementSubject);
-
-            return statment;
-        } catch (AttributeRequestException e) {
-            log.error("Error resolving attributes for SAML request from relying party "
-                    + requestContext.getRelyingPartyId(), e);
-            throw e;
-        }
-    }
-
-    /**
-     * Creates an attribute query context from the current profile request context.
-     * 
-     * @param requestContext current profile request
-     * 
-     * @return created query context
-     */
-    protected ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> buildAttributeRequestContext(
-            AttributeQueryContext requestContext) {
-
-        ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery> queryContext = new ShibbolethSAMLAttributeRequestContext<NameIdentifier, AttributeQuery>(
-                getMetadataProvider(), requestContext.getRelyingPartyConfiguration(), requestContext.getSamlRequest());
-
-        queryContext.setAttributeRequester(requestContext.getAssertingPartyId());
-        queryContext.setPrincipalName(requestContext.getPrincipalName());
-        queryContext.setProfileConfiguration(requestContext.getProfileConfiguration());
-        queryContext.setRequest(requestContext.getProfileRequest());
-
-        Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
-        if (userSession != null) {
-            queryContext.setUserSession(userSession);
-            ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
-            if (serviceInfo != null) {
-                String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
-
-                requestContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
-                queryContext.setPrincipalAuthenticationMethod(principalAuthenticationMethod);
-            }
-        }
-
-        return queryContext;
-    }
-
-    /**
      * Encodes the request's SAML response and writes it to the servlet response.
      * 
      * @param requestContext current request context
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSO.java b/src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSO.java
deleted file mode 100644 (file)
index a17f2ff..0000000
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package edu.internet2.middleware.shibboleth.idp.profile.saml1;
-
-import java.io.UnsupportedEncodingException;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
-import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
-import edu.internet2.middleware.shibboleth.common.relyingparty.ProfileConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
-import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.ShibbolethSSOConfiguration;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-
-
-import org.apache.log4j.Logger;
-import org.bouncycastle.util.encoders.Hex;
-import org.joda.time.DateTime;
-import org.opensaml.common.SAMLObjectBuilder;
-import org.opensaml.saml1.core.Assertion;
-import org.opensaml.saml1.core.Audience;
-import org.opensaml.saml1.core.AudienceRestrictionCondition;
-import org.opensaml.saml1.core.AuthenticationStatement;
-import org.opensaml.saml1.core.Conditions;
-import org.opensaml.saml1.core.ConfirmationMethod;
-import org.opensaml.saml1.core.NameIdentifier;
-import org.opensaml.saml1.core.Response;
-import org.opensaml.saml1.core.Status;
-import org.opensaml.saml1.core.Subject;
-import org.opensaml.saml1.core.SubjectConfirmation;
-import org.opensaml.saml2.metadata.AssertionConsumerService;
-import org.opensaml.saml2.metadata.Endpoint;
-import org.opensaml.saml2.metadata.SPSSODescriptor;
-import org.opensaml.saml2.metadata.provider.MetadataProviderException;
-
-/**
- * Shibboleth, version 1.X, single sign-on profile handler.
- *
- * This profile implements the SSO profile from "Shibboleth Architecture Protocols and Profiles" - 10 September 2005.
- */
-public class ShibbolethSSO extends AbstractSAML1ProfileHandler {
-    
-    
-    /**
-     * Request context for a ShibbolethSSO request.
-     */
-    protected class ShibbolethSSORequestContext {
-        
-        /** The servlet request. */
-        protected HttpServletRequest servletRequest;
-        
-        /** The servlet response. */
-        protected HttpServletResponse servletResponse;
-        
-        /** The profile request. */
-        protected ProfileRequest<ServletRequest> profileRequest;
-        
-        /** The profile response. */
-        protected ProfileResponse<ServletResponse> profileResponse;
-        
-        /** The AssertionConsumerService ("shire") URL. */
-        protected String shire;
-        
-        /** The location to which the response should be sent ("target"). */
-        protected String target;
-        
-        /** The SP's providerId in the metadata. */
-        protected String providerId;
-        
-        /** The requestor's address. */
-        protected String remoteAddr;
-        
-        /** The Shibboleth {@link LoginContext}. */
-        protected LoginContext loginContex;
-        
-        /** The RelyingPartyConfiguration for the request. */
-        protected RelyingPartyConfiguration rpConfiguration;
-        
-        /** The ShibbolethSSOConfiguration. */
-        protected ShibbolethSSOConfiguration shibSSOConfiguration;
-        
-        /** The SPSSODescriptor. */
-        protected SPSSODescriptor spDescriptor;
-        
-        /** The AssertionConsumerService to which the assertion should be sent. */
-        protected AssertionConsumerService assertionConsumerService;
-        
-        /** The Assertion we generate in response. */
-        protected Assertion assertion;
-        
-        public ShibbolethSSORequestContext() {
-        }
-        
-        public ShibbolethSSORequestContext(final ProfileRequest<ServletRequest> profileRequest,
-                final ProfileResponse<ServletResponse> profileResponse, String shire, String target,
-                String providerId, String remoteAddr) {
-            
-            this.profileRequest = profileRequest;
-            this.profileResponse = profileResponse;
-            this.servletRequest = (HttpServletRequest) profileRequest.getRawRequest();
-            this.servletResponse = (HttpServletResponse) profileResponse.getRawResponse();
-            this.shire = shire;
-            this.target = target;
-            this.providerId = providerId;
-            this.remoteAddr = remoteAddr;
-        }
-        
-        public ProfileRequest<ServletRequest> getProfileRequest() {
-            return profileRequest;
-        }
-        
-        public void setProfileRequest(ProfileRequest<ServletRequest> profileRequest) {
-            this.profileRequest = profileRequest;
-            this.servletRequest = (HttpServletRequest) profileRequest.getRawRequest();
-        }
-        
-        public ProfileResponse<ServletResponse> getProfileResponse() {
-            return profileResponse;
-        }
-        
-        public void setProfileResponse(ProfileResponse<ServletResponse> profileResponse) {
-            this.profileResponse = profileResponse;
-            this.servletResponse = (HttpServletResponse) profileResponse.getRawResponse();
-        }
-        
-        public HttpServletRequest getServletRequest() {
-            return servletRequest;
-        }
-        
-        public void setServletRequest(HttpServletRequest servletRequest) {
-            this.servletRequest = servletRequest;
-        }
-        
-        public HttpServletResponse getServletResponse() {
-            return servletResponse;
-        }
-        
-        public void setServletResponse(HttpServletResponse servletResponse) {
-            this.servletResponse = servletResponse;
-        }
-        
-        public String getShire() {
-            return shire;
-        }
-        
-        public void setShire(String shire) {
-            this.shire = shire;
-        }
-        
-        public String getTarget() {
-            return target;
-        }
-        
-        public void setTarget(String target) {
-            this.target = target;
-        }
-        
-        public String getProviderId() {
-            return providerId;
-        }
-        
-        public void setProviderId(String providerId) {
-            this.providerId = providerId;
-        }
-        
-        public String getRemoteAddr() {
-            return remoteAddr;
-        }
-        
-        public void setRemoteAddr(String remoteAddr) {
-            this.remoteAddr = remoteAddr;
-        }
-        
-        public LoginContext getLoginContex() {
-            return loginContex;
-        }
-        
-        public void setLoginContex(LoginContext loginContext) {
-            
-            this.loginContex = loginContext;
-            
-            if (loginContext.getProfileHandlerURL() == null) {
-                loginContext.setProfileHandlerURL(getServletRequest().getRequestURI());
-            }
-            
-            getHttpSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
-        }
-        
-        public RelyingPartyConfiguration getRpConfiguration() {
-            return rpConfiguration;
-        }
-        
-        public void setRpConfiguration(RelyingPartyConfiguration rpConfiguration) {
-            this.rpConfiguration = rpConfiguration;
-        }
-        
-        public Assertion getAssertion() {
-            return assertion;
-        }
-        
-        public void setAssertion(Assertion assertion) {
-            this.assertion = assertion;
-        }
-        
-        public ShibbolethSSOConfiguration getShibSSOConfiguration() {
-            return shibSSOConfiguration;
-        }
-        
-        public void setShibSSOConfiguration(ShibbolethSSOConfiguration shibSSOConfiguration) {
-            this.shibSSOConfiguration = shibSSOConfiguration;
-        }
-        
-        public SPSSODescriptor getSpDescriptor() {
-            return spDescriptor;
-        }
-        
-        public void setSpDescriptor(SPSSODescriptor spDescriptor) {
-            this.spDescriptor = spDescriptor;
-        }
-        
-        public AssertionConsumerService getAssertionConsumerService() {
-            return assertionConsumerService;
-        }
-        
-        public void setAssertionConsumerService(AssertionConsumerService assertionConsumers) {
-            this.assertionConsumerService = assertionConsumers;
-        }
-        
-        
-        public HttpSession getHttpSession() {
-            
-            if (getServletRequest() != null) {
-                return getServletRequest().getSession();
-            } else {
-                return null;
-            }
-        }
-        
-        public boolean equals(final Object obj) {
-            
-            if (obj == null) {
-                return false;
-            }
-            
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            
-            final ShibbolethSSORequestContext other = (ShibbolethSSORequestContext) obj;
-            
-            if (servletRequest != other.servletRequest && (servletRequest == null || !this.servletRequest.equals(other.servletRequest))) {
-                return false;
-            }
-            
-            if (servletResponse != other.servletResponse && (servletResponse == null || !this.servletResponse.equals(other.servletResponse))) {
-                return false;
-            }
-            
-            if (shire != other.shire && (shire == null || !shire.equals(other.shire))) {
-                return false;
-            }
-            
-            if (target != other.target && (target == null || !target.equals(other.target))) {
-                return false;
-            }
-            
-            if (providerId != other.providerId && (providerId == null || !providerId.equals(other.providerId))) {
-                return false;
-            }
-            
-            if (remoteAddr != other.remoteAddr && (remoteAddr == null || !remoteAddr.equals(other.remoteAddr))) {
-                return false;
-            }
-            
-            return true;
-        }
-        
-        public int hashCode() {
-            
-            int hash = 7;
-            hash = 71 * hash + shire != null ? shire.hashCode() : 0;
-            hash = 71 * hash + target != null ? target.hashCode() : 0;
-            hash = 71 * hash + providerId != null ? providerId.hashCode() : 0;
-            hash = 71 * hash + remoteAddr != null ? remoteAddr.hashCode() : 0;
-            
-            return hash;
-        }
-    }
-    
-    /**
-     * Internal exception class used by utilty methods.
-     */
-    protected class ShibbolethSSOException extends Exception {
-        
-        public ShibbolethSSOException() {
-        }
-        
-        public ShibbolethSSOException(final String message) {
-            super(message);
-        }
-        
-        public ShibbolethSSOException(final Throwable cause) {
-            super(cause);
-        }
-        
-        public ShibbolethSSOException(final String message, final Throwable cause) {
-            super(message, cause);
-        }
-        
-    }
-    
-    
-    /** 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 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 protocol URI. */
-    protected static final String PROFILE_ARTIFACT_URI = "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01";
-    
-    /** The digest algorithm for generating SP cookies. */
-    protected static final String RP_COOKIE_DIGEST_ALG = "SHA-1";
-    
-    /** Profile ID for this handler. */
-    protected static final String PROFILE_ID = "urn:mace:shibboleth:1.0:profiles:AuthnRequest";
-    
-    /** The request parameter containing the time the request was made. */
-    protected static final String REQUEST_PARAMETER_TIME = "time";
-    
-    /** HttpSession key for the ShibbolethSSORequestContext. */
-    protected static final String REQUEST_CONTEXT_SESSION_KEY = "edu.internet2.middleware.shibboleth.idp.profile.saml1.ShibbolethSSORequestContext";
-    
-    /** The path to the IdP's AuthenticationManager servlet */
-    protected String authnMgrURL;
-    
-    /** The URI of the default authentication method */
-    protected String authenticationMethodURI;
-    
-    /** Builder for AuthenticationStatement objects. */
-    protected SAMLObjectBuilder<AuthenticationStatement> authnStmtBuilder;
-    
-    /** Builder for Subject elements. */
-    protected SAMLObjectBuilder<Subject> subjectBuilder;
-    
-    /** Builder for SubjectConfirmation objects. */
-    protected SAMLObjectBuilder<SubjectConfirmation> subjConfBuilder;
-    
-    /** Builder for SubjectConfirmationMethod objects. */
-    protected SAMLObjectBuilder<ConfirmationMethod> confMethodBuilder;
-    
-    /** Builder for NameIdentifiers. */
-    protected SAMLObjectBuilder<NameIdentifier> nameIdentifierBuilder;
-    
-    /** Builder for Audience elements. */
-    protected SAMLObjectBuilder<Audience> audienceBuilder;
-    
-    /** Builder for AudienceRestrictionCondition elements. */
-    protected SAMLObjectBuilder<AudienceRestrictionCondition> audienceRestrictionBuilder;
-    
-    /** Builder for Assertions. */
-    protected SAMLObjectBuilder<Assertion> assertionBuilder;
-    
-    /** Builder for Response objects. */
-    protected SAMLObjectBuilder<Response> responseBuilder;
-    
-    /** Block stale requests. */
-    protected boolean blockStaleRequests = false;
-    
-    /**
-     * Time after which an authn request is considered stale (in seconds). Defaults to 30 minutes.
-     */
-    protected int requestTTL = 1800;
-    
-    /**
-     * Default constructor.
-     */
-    public ShibbolethSSO() {
-        
-        // setup SAML object builders
-        
-        assertionBuilder           = (SAMLObjectBuilder<Assertion>) getBuilderFactory().getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
-        authnStmtBuilder           = (SAMLObjectBuilder<AuthenticationStatement>) getBuilderFactory().getBuilder(AuthenticationStatement.DEFAULT_ELEMENT_NAME);
-        subjectBuilder             = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
-        subjConfBuilder            = (SAMLObjectBuilder<SubjectConfirmation>) getBuilderFactory().getBuilder(SubjectConfirmation.DEFAULT_ELEMENT_NAME);
-        confMethodBuilder          = (SAMLObjectBuilder<ConfirmationMethod>) getBuilderFactory().getBuilder(ConfirmationMethod.DEFAULT_ELEMENT_NAME);
-        nameIdentifierBuilder      = (SAMLObjectBuilder<NameIdentifier>) getBuilderFactory().getBuilder(NameIdentifier.DEFAULT_ELEMENT_NAME);
-        audienceBuilder            = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
-        audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestrictionCondition>) getBuilderFactory().getBuilder(AudienceRestrictionCondition.DEFAULT_ELEMENT_NAME);
-        responseBuilder            = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
-        
-    }
-    
-    /** {@inheritDoc} */
-    public String getProfileId() {
-        return PROFILE_ID;
-    }
-    
-    /**
-     * Set the authentication manager.
-     *
-     * @param authnManagerURL The URL of the IdP's AuthenticationManager servlet
-     */
-    public void setAuthenticationManager(String authnManagerURL) {
-        authnMgrURL = authnManagerURL;
-    }
-    
-    /**
-     * 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;
-    }
-    
-    /** {@inheritDoc} */
-    public void processRequest(final ProfileRequest<ServletRequest> request, final ProfileResponse<ServletResponse> response) throws ProfileException {
-        
-        // Only http servlets are supported for now.
-        if (!(request.getRawRequest() instanceof HttpServletRequest)) {
-            log.error("Received a non-HTTP request.");
-            throw new ProfileException("Received a non-HTTP request.");
-        }
-        
-        // This method is called twice.
-        // On the first time, there will be no ShibbolethSSORequestContext object. We redirect control to the
-        // AuthenticationManager to authenticate the user. The AuthenticationManager then redirects control
-        // back to this servlet. On the "return leg" connection, there will be a ShibbolethSSORequestContext object.
-        
-        HttpServletRequest req = (HttpServletRequest) request.getRawRequest();
-        Object o = req.getSession().getAttribute(REQUEST_CONTEXT_SESSION_KEY);
-        if (o != null && !(o instanceof ShibbolethSSORequestContext)) {
-            log.error("SAML 1 Authentication Request Handler: Invalid session data found for ShibbolethSSORequestContext");
-            throw new ProfileException("SAML 1 Authentication Request Handler: Invalid session data found for ShibbolethSSORequestContext");
-        }
-        
-        if (o == null) {
-            setupNewRequest(request, response);
-        } else {
-            
-            ShibbolethSSORequestContext requestContext = (ShibbolethSSORequestContext)o;
-            
-            // clean up the HttpSession.
-            requestContext.getHttpSession().removeAttribute(REQUEST_CONTEXT_SESSION_KEY);
-            requestContext.getHttpSession().removeAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-            
-            finishProcessingRequest(requestContext);
-        }
-    }
-    
-    /**
-     * Begin processing a SAML 1.x authentication request.
-     * This ensurues that the request is well-formed and that
-     * appropriate metadata can be found for the SP.
-     * Once these conditions are met, control is passed to
-     * the AuthenticationManager to authenticate the user.
-     *
-     * @param request The ProfileRequest.
-     * @param response The ProfileResponse.
-     *
-     * @throws ProfileException On error.
-     */
-    protected void setupNewRequest(final ProfileRequest<ServletRequest> request, final ProfileResponse<ServletResponse> response) throws ProfileException {
-        
-        try {
-            ShibbolethSSORequestContext requestContext = new ShibbolethSSORequestContext();
-            requestContext.setProfileRequest(request);
-            requestContext.setProfileResponse(response);
-            
-            // extract the (mandatory) request parameters.
-            getRequestParameters(requestContext);
-            
-            // check that we have metadata for the SP
-            validateRequestAgainstMetadata(requestContext);
-            
-            // check for stale requests
-            if (blockStaleRequests) {
-                String cookieName = getRPCookieName(requestContext.getProviderId());
-                if (!validateFreshness(requestContext, cookieName)) {
-                    log.error("SAML 1 Authentication Request Handler: detected stale authentiation request");
-                    throw new ProfileException("SAML 1 Authentication Request Handler: detected stale authentication request");
-                }
-                
-                writeFreshnessCookie(requestContext, cookieName);
-            }
-            
-            // don't force reauth or passive auth
-            requestContext.setLoginContex(new LoginContext(false, false));
-            
-            try {
-                // put the request context object in the HttpSession, so we can retrieve it on the "return leg"
-                requestContext.getHttpSession().setAttribute(REQUEST_CONTEXT_SESSION_KEY, requestContext);
-                
-                // the AuthenticationManager expects the LoginContext to be in the HttpSession too.
-                requestContext.getHttpSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, requestContext.getLoginContex());
-                
-                // forward control to the AuthenticationManager
-                RequestDispatcher dispatcher = requestContext.getServletRequest().getRequestDispatcher(authnMgrURL);
-                dispatcher.forward(requestContext.getServletRequest(), requestContext.getServletResponse());
-            } catch (IOException ex) {
-                log.error("SAML 1 Authentication Request Handler: Error forwarding SAML 1 SSO request to AuthenticationManager", ex);
-                throw new ProfileException("Error forwarding SAML 1 SSO request to AuthenticationManager", ex);
-            } catch (ServletException ex) {
-                log.error("SAML 1 Authentication Request Handler: Error forwarding SAML 1 SSO request to AuthenticationManager", ex);
-                throw new ProfileException("Error forwarding SAML 1 SSO request to AuthenticationManager", ex);
-            }
-            
-        } catch (ShibbolethSSOException ex) {
-            log.error("SAML 1 Authentication Request Handler: Error processing Shibboleth SSO request", ex);
-            throw new ProfileException("Error processing Shibboleth SSO request", ex);
-        }
-    }
-    
-    
-    /**
-     * Process the "return leg" of a SAML 1 authentication request.
-     *
-     * This evaluates the AuthenticationManager's LoginContext, and generates an Authentication Assertion, as appropriate.
-     *
-     * @param requestContext The context for the request.
-     *
-     * @throws ProfileException On error.
-     */
-    protected void finishProcessingRequest(final ShibbolethSSORequestContext requestContext) throws ProfileException {
-        
-        // If the user successfully authenticated
-        // build the appropriate AuthenticationStatement.
-        if (requestContext.getLoginContex().getAuthenticationOK()) {
-            DateTime now = new DateTime();
-            generateAuthenticationAssertion(requestContext, now);
-        }
-        
-        encodeSAMLResponse(requestContext);
-    }
-    
-    /**
-     * Encode the SAML response.
-     *
-     * @param requestContext The context for the request.
-     *
-     * @throws ProfileException On error.
-     */
-    protected void encodeSAMLResponse(final ShibbolethSSORequestContext requestContext) throws ProfileException {
-        
-        Response samlResponse = responseBuilder.buildObject();
-        samlResponse.setID(getIdGenerator().generateIdentifier());
-        samlResponse.setIssueInstant(new DateTime());
-        samlResponse.setVersion(SAML_VERSION);
-        samlResponse.setRecipient(requestContext.getProviderId());
-        
-        Status status;
-        
-        // If AuthN failed, and if we're using the Artifact binding, we don't send a failure message.
-        if (!(requestContext.getLoginContex().getAuthenticationOK()) 
-                && (requestContext.getAssertionConsumerService().getBinding().equals(PROFILE_ARTIFACT_URI))) {
-            
-            log.error("SAML 1 Authentication Request Handler: Authentication failed but using the Artifact binding for SP " +
-                    requestContext.getProviderId());
-            return;
-        }
-        
-        if (requestContext.getLoginContex().getAuthenticationOK()) {
-            status = buildStatus("Success", null);
-            List<Assertion> assertionList = samlResponse.getAssertions();
-            assertionList.add(requestContext.getAssertion());
-        } else {
-            status = buildStatus("Responder", null);
-        }
-        
-        samlResponse.setStatus(status);
-        
-        encodeResponse(PROFILE_ID, requestContext.getProfileResponse(), samlResponse,
-                requestContext.getRpConfiguration(), requestContext.getSpDescriptor(),
-                (Endpoint) requestContext.getAssertionConsumerService());
-    }
-    
-    /**
-     * Get the Shibboleth profile-specific request parameters.
-     *
-     * @param request The servlet request from the SP.
-     * @param response The servlet response.
-     *
-     * @throw ShibbolethSSOException On Error.
-     */
-    protected void getRequestParameters(final ShibbolethSSORequestContext requestContext) throws ShibbolethSSOException {
-        
-        HttpServletRequest servletRequest = requestContext.getServletRequest();
-        
-        String target = servletRequest.getParameter("target");
-        String providerId = servletRequest.getParameter("providerId");
-        String shire = servletRequest.getParameter("shire");
-        String remoteAddr = servletRequest.getRemoteAddr();
-        
-        if (target == null || target.equals("")) {
-            log.error("SAML 1 Authentication Request Handler: Shib 1 SSO request is missing or contains an invalid target parameter");
-            throw new ShibbolethSSOException("Shib 1 SSO request is missing or contains an invalid target parameter");
-        }
-        
-        if (providerId == null || providerId.equals("")) {
-            log.error("SAML 1 Authentication Request Handler: Shib 1 SSO request is missing or contains an invalid provierId parameter");
-            throw new ShibbolethSSOException("Shib 1 SSO request is missing or contains an invalid provierId parameter");
-        }
-        
-        if (shire == null || providerId.equals("")) {
-            log.error("SAML 1 Authentication Request Handler: Shib 1 SSO request is missing or contains an invalid shire parameter");
-            throw new ShibbolethSSOException("Shib 1 SSO request is missing or contains an invalid shire parameter");
-        }
-        
-        if (remoteAddr == null || remoteAddr.equals("")) {
-            log.error("SAML 1 Authentication Request Handler: Unable to obtain requestor address when processing Shib 1 SSO request");
-            throw new ShibbolethSSOException("Unable to obtain requestor address when processing Shib 1 SSO request");
-        }
-        
-        requestContext.setTarget(target);
-        requestContext.setProviderId(providerId);
-        requestContext.setShire(shire);
-        requestContext.setRemoteAddr(remoteAddr);
-    }
-    
-    /**
-     * Generate a SAML 1 AuthenticationStatement.
-     *
-     * @param requestContext The context for the ShibbolethSSO request.
-     * @param now The current timestamp
-     *
-     * @return A SAML 1 Authentication Assertion or <code>null</code> on error.
-     */
-    protected Assertion generateAuthenticationAssertion(final ShibbolethSSORequestContext requestContext,
-            final DateTime now) {
-        
-        String providerId = requestContext.getRpConfiguration().getProviderId();
-        
-        Assertion authenticationAssertion = assertionBuilder.buildObject();
-        authenticationAssertion.setIssueInstant(now);
-        authenticationAssertion.setVersion(SAML_VERSION);
-        authenticationAssertion.setIssuer(providerId);
-        authenticationAssertion.setID(getIdGenerator().generateIdentifier());
-        
-        Conditions conditions = authenticationAssertion.getConditions();
-        conditions.setNotBefore(now.minusSeconds(30)); // for now, clock skew is hard-coded to 30 seconds.
-        conditions.setNotOnOrAfter(now.plusMillis((int)requestContext.getShibSSOConfiguration().getAssertionLifetime()));
-        
-        List<AudienceRestrictionCondition> audienceRestrictions = conditions.getAudienceRestrictionConditions();
-        AudienceRestrictionCondition restrictionCondition = audienceRestrictionBuilder.buildObject();
-        audienceRestrictions.add(restrictionCondition);
-        
-        // add the RelyingParty to the audience.
-        Audience rpAudience = audienceBuilder.buildObject();
-        rpAudience.setUri(requestContext.getRpConfiguration().getProviderId());
-        restrictionCondition.getAudiences().add(rpAudience);
-        
-        // if necessary, explicitely add the SP to the audience.
-        if (!providerId.equals(requestContext.getProviderId())) {
-            Audience spAudience = (Audience) audienceBuilder.buildObject();
-            spAudience.setUri(requestContext.getProviderId());
-            restrictionCondition.getAudiences().add(spAudience);
-        }
-        
-        AuthenticationStatement authenticationStatement = authnStmtBuilder.buildObject();
-        authenticationStatement.setSubject(buildSubject(requestContext));
-        authenticationStatement.setAuthenticationInstant(requestContext.getLoginContex().getAuthenticationInstant());
-        authenticationStatement.setAuthenticationMethod(authenticationMethodURI);
-        
-        authenticationAssertion.getAuthenticationStatements().add(authenticationStatement);
-        
-        if (requestContext.getSpDescriptor().getWantAssertionsSigned()) {
-            signAssertion(authenticationAssertion, requestContext.getRpConfiguration(), requestContext.getShibSSOConfiguration());
-        }
-        
-        return authenticationAssertion;
-    }
-    
-    
-    /**
-     * Ensure that metadata can be found for the authentication request.
-     * If found, the request context is updated to reflect the appropriate entries.
-     *
-     * @param requestContext The context for the current request.
-     *
-     * @throws ShibbolethSSOException On error.
-     */
-    protected void validateRequestAgainstMetadata(final ShibbolethSSORequestContext requestContext) throws ShibbolethSSOException {
-        
-        RelyingPartyConfiguration relyingParty = getRelyingPartyConfigurationManager().getRelyingPartyConfiguration(requestContext.getProviderId());
-        ProfileConfiguration temp = relyingParty.getProfileConfigurations().get(ShibbolethSSOConfiguration.PROFILE_ID);
-        if (temp == null) {
-            log.error("SAML 1 Authentication Request Handler: No profile configuration registered for " + ShibbolethSSOConfiguration.PROFILE_ID);
-            throw new ShibbolethSSOException("No profile configuration registered for " + ShibbolethSSOConfiguration.PROFILE_ID);
-        }
-        
-        ShibbolethSSOConfiguration ssoConfig = (ShibbolethSSOConfiguration) temp;
-        SPSSODescriptor spDescriptor;
-        
-        try {
-            spDescriptor = getMetadataProvider().getEntityDescriptor(relyingParty.getRelyingPartyId()).getSPSSODescriptor(SAML11_PROTOCOL_URI);
-        } catch (MetadataProviderException ex) {
-            log.error("SAML 1 Authentication Request Handler: Unable to locate metadata for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI, ex);
-            throw new ShibbolethSSOException("Unable to locate metadata for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI, ex);
-        }
-        
-        if (spDescriptor == null) {
-            log.error("SAML 1 Authentication Request Handler: Unable to locate metadata for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI);
-            throw new ShibbolethSSOException("Unable to locate metadata for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI);
-        }
-        
-        
-        // validate the AssertionConsumer ("shire") URL against the AssertionConsumerService endpoints in the metadata.
-        if (!(evaluateACSEndpoint(requestContext, requestContext.getSpDescriptor().getDefaultAssertionConsumerService()))) {
-            
-            // if the default AssertionConsumerService endpoint was not valid, iterate over all remaining endpoints.
-            boolean found = false;
-            for (AssertionConsumerService candidateEndpoint : requestContext.getSpDescriptor().getAssertionConsumerServices()) {
-                if (evaluateACSEndpoint(requestContext, candidateEndpoint)) {
-                    found = true;
-                    break;
-                }
-            }
-            
-            if (!found) {
-                log.error("SAML 1 Authentication Request Handler: Unable to find AssertionConsumerService " +
-                        requestContext.getShire() + " for SP " + requestContext.getProviderId() +
-                        " for protocol " + SAML11_PROTOCOL_URI);
-                throw new ShibbolethSSOException("Unable to find AssertionConsumerService " +
-                        requestContext.getShire() + " for SP " + requestContext.getProviderId() +
-                        " for protocol " + SAML11_PROTOCOL_URI);
-            }
-        }
-        
-        
-        // spDescriptor returns a reference to an internal mutable copy, so make a copy of it.
-        List<AssertionConsumerService> consumerURLs =
-                new ArrayList<AssertionConsumerService>(requestContext.getSpDescriptor().getAssertionConsumerServices().size());
-        
-        // filter out any list elements that don't have the correct location field.
-        // copy any consumerURLs with the correct location
-        for (AssertionConsumerService service : requestContext.getSpDescriptor().getAssertionConsumerServices()) {
-            if (service.getLocation().equals(requestContext.getShire())) {
-                consumerURLs.add(service);
-            }
-        }
-        if (consumerURLs.size() == 0) {
-            log.error("SAML 1 Authentication Request Handler: Unable to validate AssertionConsumerService URL against metadata: " + requestContext.getShire()
-                    + " not found for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI);
-            throw new ShibbolethSSOException("Unable to validate AssertionConsumerService URL against metadata: " + requestContext.getShire()
-                    + " not found for SP " + requestContext.getProviderId() + " for protocol " + SAML11_PROTOCOL_URI);
-        }
-        
-        requestContext.setRpConfiguration(relyingParty);
-        requestContext.setShibSSOConfiguration(ssoConfig);
-        requestContext.setSpDescriptor(spDescriptor);
-    }
-    
-    
-    /**
-     * Evaluate a specific AssertionConsumerService endpoint against the request's "shire" parameter.
-     * If it matches, update the request context to use this endpoint.
-     *
-     * @param requestContext The context for the current request.
-     * @param candidateEndpoint An endpoint to consider for use for the response.
-     *
-     * @return <code>true</code> if <code>candidateEndpoint</code> is valid; otherwise, <code>false</code>.
-     */
-    protected boolean evaluateACSEndpoint(final ShibbolethSSORequestContext requestContext, final AssertionConsumerService candidateEndpoint) {
-        
-        if (requestContext.getShire().equals(candidateEndpoint.getLocation())) {
-            requestContext.setAssertionConsumerService(candidateEndpoint);
-            return true;
-        } else {
-            return false;
-        }
-    }
-    
-    
-    
-    /**
-     * Validate the "freshness" of an authn request. If the reqeust is more than 30 minutes old, reject it.
-     *
-     * @param requestContext The context for the current request.
-     * @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(final ShibbolethSSORequestContext requestContext, String cookieName) {
-        
-        if (cookieName == null) {
-            return false;
-        }
-        
-        String timestamp = requestContext.getServletRequest().getParameter(REQUEST_PARAMETER_TIME);
-        if (timestamp == null || timestamp.equals("")) {
-            return true;
-        }
-        
-        long reqtime;
-        try {
-            reqtime = Long.parseLong(timestamp);
-        } catch (NumberFormatException ex) {
-            log.error("SAML 1 Authentication Request Handler: Unable to parse Authentication Request's timestamp", ex);
-            return false;
-        }
-        
-        if (reqtime * 1000 < (System.currentTimeMillis() - requestTTL * 1000)) {
-            return false;
-        }
-        
-        for (Cookie cookie : requestContext.getServletRequest().getCookies()) {
-            if (cookieName.equals(cookie.getName())) {
-                try {
-                    long cookieTime = Long.parseLong(cookie.getValue());
-                    if (reqtime <= cookieTime) {
-                        return false;
-                    }
-                } catch (NumberFormatException ex) {
-                    log.error("SAML 1 Authentication Request Handler: 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 ProfileException If unable to find a JCE provider for SHA-1
-     *
-     * @return the RP's cookie name
-     */
-    protected String getRPCookieName(String providerID) throws ProfileException {
-        
-        try {
-            MessageDigest digester = MessageDigest.getInstance(RP_COOKIE_DIGEST_ALG);
-            return "shib_sp_" + new String(Hex.encode(digester.digest(providerID.getBytes("UTF-8"))));
-        } catch (NoSuchAlgorithmException ex) {
-            throw new ProfileException("Unabel to create RPCookie", ex);
-        } catch (UnsupportedEncodingException ex) {
-            // this should never happen. UTF-8 encoding should always be supported.
-            throw new ProfileException("Unable to locate UTF-8 encoder", ex);
-        }
-    }
-    
-    /**
-     * Write the current time into the freshness cookie.
-     *
-     * @param requestContext The context for the current request.
-     * @param cookieName The name of the cookie to write.
-     */
-    protected void writeFreshnessCookie(final ShibbolethSSORequestContext requestContext, String cookieName) {
-        
-        String timestamp = requestContext.getServletRequest().getParameter("time");
-        if (timestamp == null || timestamp.equals("")) {
-            return;
-        }
-        
-        Cookie cookie = new Cookie(cookieName, timestamp);
-        cookie.setSecure(true);
-        requestContext.getServletResponse().addCookie(cookie);
-    }
-    
-    /**
-     * Generate a SAML 1 Subject element.
-     *
-     * @param requestContext The context for the current request.
-     *
-     * @return a Subject object.
-     */
-    protected Subject buildSubject(final ShibbolethSSORequestContext requestContext) {
-        
-        LoginContext loginContext = requestContext.getLoginContex();
-        ShibbolethSSOConfiguration ssoConfig =  requestContext.getShibSSOConfiguration();
-        
-        String protocolBinding = requestContext.getAssertionConsumerService().getBinding();
-        String confirmationMethod = null;
-        
-        // Set the SubjectConfirmationMethod appropriately depending on the protocol binding
-        if (protocolBinding.equals(PROFILE_ARTIFACT_URI)) {
-            confirmationMethod = ARTIFACT_CONF_METHOD_URI;
-        } else if (protocolBinding.equals(PROFILE_BROWSER_POST_URI)) {
-            confirmationMethod = BEARER_CONF_METHOD_URI;
-        }
-        
-        Subject subject = subjectBuilder.buildObject();
-        
-        NameIdentifier nameID = nameIdentifierBuilder.buildObject();
-        nameID.setFormat(ssoConfig.getSubjectNameFormat());
-        
-        String username = loginContext.getUserID();
-        
-        // XXX: todo: map the username onto an appropriate format
-        nameID.setNameQualifier(username);
-        
-        if (confirmationMethod != null) {
-            
-            ConfirmationMethod m = confMethodBuilder.buildObject();
-            m.setConfirmationMethod(confirmationMethod);
-            
-            SubjectConfirmation subjConf = subjConfBuilder.buildObject();
-            subjConf.getConfirmationMethods().add(m);
-            subject.setSubjectConfirmation(subjConf);
-        }
-        
-        return subject;
-    }
-}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSOProfileHandler.java b/src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSOProfileHandler.java
new file mode 100644 (file)
index 0000000..adf03e7
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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.saml1;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+
+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 org.apache.log4j.Logger;
+import org.opensaml.common.SAMLObject;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.common.binding.BindingException;
+import org.opensaml.common.binding.encoding.MessageEncoder;
+import org.opensaml.saml1.core.AuthenticationStatement;
+import org.opensaml.saml1.core.Response;
+import org.opensaml.saml1.core.Statement;
+import org.opensaml.saml1.core.StatusCode;
+import org.opensaml.saml1.core.Subject;
+import org.opensaml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.xml.util.DatatypeHelper;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileRequest;
+import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
+import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
+import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.ShibbolethSSOConfiguration;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+import edu.internet2.middleware.shibboleth.idp.authn.ShibbolethSSOLoginContext;
+
+/** Shibboleth SSO request profile handler. */
+public class ShibbolethSSOProfileHandler extends AbstractSAML1ProfileHandler {
+
+    /** Class logger. */
+    private final Logger log = Logger.getLogger(ShibbolethSSOProfileHandler.class);
+
+    /** Builder of AuthenticationStatement objects. */
+    private SAMLObjectBuilder<AuthenticationStatement> authnStatementBuilder;
+
+    /** URL of the authentication manager servlet. */
+    private String authenticationManagerPath;
+
+    /** Message encoder binding URI. */
+    private String encodingBinding;
+
+    /**
+     * Constructor.
+     * 
+     * @param authnManagerPath path to the authentication manager servlet
+     * @param encoder URI of the encoding binding
+     * 
+     * @throws IllegalArgumentException thrown if either the authentication manager path or encoding binding URI are
+     *             null or empty
+     */
+    public ShibbolethSSOProfileHandler(String authnManagerPath, String encoder) {
+        if (DatatypeHelper.isEmpty(authnManagerPath) || DatatypeHelper.isEmpty(encoder)) {
+            throw new IllegalArgumentException("Authentication manager path and encoder binding URI may not be null");
+        }
+
+        authenticationManagerPath = authnManagerPath;
+        encodingBinding = encoder;
+
+        authnStatementBuilder = (SAMLObjectBuilder<AuthenticationStatement>) getBuilderFactory().getBuilder(
+                AuthenticationStatement.DEFAULT_ELEMENT_NAME);
+    }
+
+    /**
+     * Convenience method for getting the SAML 1 AuthenticationStatement builder.
+     * 
+     * @return SAML 1 AuthenticationStatement builder
+     */
+    public SAMLObjectBuilder<AuthenticationStatement> getAuthenticationStatementBuilder() {
+        return authnStatementBuilder;
+    }
+
+    /** {@inheritDoc} */
+    public String getProfileId() {
+        return "urn:mace:shibboleth:2.0:idp:profiles:shibboleth:request:sso";
+    }
+
+    /** {@inheritDoc} */
+    public void processRequest(ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response)
+            throws ProfileException {
+
+        HttpSession httpSession = ((HttpServletRequest) request.getRawRequest()).getSession(true);
+        if (httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY) == null) {
+            performAuthentication(request, response);
+        } else {
+            completeAuthenticationRequest(request, response);
+        }
+    }
+
+    /**
+     * Creates a {@link LoginContext} an sends the request off to the AuthenticationManager to begin the process of
+     * authenticating the user.
+     * 
+     * @param request current request
+     * @param response current response
+     * 
+     * @throws ProfileException thrown if there is a problem creating the login context and transferring control to the
+     *             authentication manager
+     */
+    protected void performAuthentication(ProfileRequest<ServletRequest> request,
+            ProfileResponse<ServletResponse> response) throws ProfileException {
+
+        HttpServletRequest httpRequest = (HttpServletRequest) request.getRawRequest();
+        HttpServletResponse httpResponse = (HttpServletResponse) response.getRawResponse();
+        HttpSession httpSession = httpRequest.getSession(true);
+
+        LoginContext loginContext = buildLoginContext(httpRequest);
+        httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+
+        try {
+            RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(authenticationManagerPath);
+            dispatcher.forward(httpRequest, httpResponse);
+        } catch (IOException ex) {
+            log.error("Error forwarding Shibboleth SSO request to AuthenticationManager", ex);
+            throw new ProfileException("Error forwarding Shibboleth SSO request to AuthenticationManager", ex);
+        } catch (ServletException ex) {
+            log.error("Error forwarding Shibboleth SSO request to AuthenticationManager", ex);
+            throw new ProfileException("Error forwarding Shibboleth SSO request to AuthenticationManager", ex);
+        }
+    }
+
+    /**
+     * Creates a response to the Shibboleth SSO and sends the user, with response in tow, back to the relying party
+     * after they've been authenticated.
+     * 
+     * @param request current request
+     * @param response current response
+     * 
+     * @throws ProfileException thrown if the response can not be created and sent back to the relying party
+     */
+    protected void completeAuthenticationRequest(ProfileRequest<ServletRequest> request,
+            ProfileResponse<ServletResponse> response) throws ProfileException {
+        HttpSession httpSession = ((HttpServletRequest) request.getRawRequest()).getSession(true);
+
+        ShibbolethSSOLoginContext loginContext = (ShibbolethSSOLoginContext) httpSession
+                .getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+        httpSession.removeAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+
+        ShibbolethSSORequestContext requestContext = buildRequestContext(loginContext, request, response);
+
+        Response samlResponse;
+        try {
+            if (!loginContext.getAuthenticationOK()) {
+                requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "User failed authentication"));
+                throw new ProfileException("User failed authentication");
+            }
+
+            ArrayList<Statement> statements = new ArrayList<Statement>();
+            statements.add(buildAuthenticationStatement(requestContext));
+            statements.add(buildAttributeStatement(requestContext, "urn:oasis:names:tc:SAML:1.0:cm:sender-vouches"));
+
+            samlResponse = buildResponse(requestContext, statements);
+        } catch (ProfileException e) {
+            samlResponse = buildErrorResponse(requestContext);
+        }
+
+        requestContext.setSamlResponse(samlResponse);
+        encodeResponse(requestContext);
+        writeAuditLogEntry(requestContext);
+    }
+
+    /**
+     * Creates a login context from the incoming HTTP request.
+     * 
+     * @param request current HTTP request
+     * 
+     * @return the constructed login context
+     * 
+     * @throws ProfileException thrown if the incomming request did not contain a providerId, shire, and target
+     *             parameter
+     */
+    protected ShibbolethSSOLoginContext buildLoginContext(HttpServletRequest request) throws ProfileException {
+        ShibbolethSSOLoginContext loginContext = new ShibbolethSSOLoginContext();
+
+        try {
+            String providerId = DatatypeHelper.safeTrimOrNullString(request.getParameter("providerId"));
+            if (providerId == null) {
+                log.error("No providerId parameter in Shibboleth SSO request");
+                throw new ProfileException("No providerId parameter in Shibboleth SSO request");
+            }
+            loginContext.setRelyingParty(URLDecoder.decode(providerId, "UTF-8"));
+
+            String acs = DatatypeHelper.safeTrimOrNullString(request.getParameter("shire"));
+            if (acs == null) {
+                log.error("No shire parameter in Shibboleth SSO request");
+                throw new ProfileException("No shire parameter in Shibboleth SSO request");
+            }
+            loginContext.setSpAssertionConsumerService(URLDecoder.decode(acs, "UTF-8"));
+
+            String target = DatatypeHelper.safeTrimOrNullString(request.getParameter("target"));
+            if (target == null) {
+                log.error("No target parameter in Shibboleth SSO request");
+                throw new ProfileException("No target parameter in Shibboleth SSO request");
+            }
+            loginContext.setSpTarget(URLDecoder.decode(target, "UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            // UTF-8 encoding required to be supported by all JVMs.
+        }
+
+        loginContext.setAuthenticationManagerURL(authenticationManagerPath);
+        loginContext.setProfileHandlerURL(request.getRequestURI());
+        return loginContext;
+    }
+
+    /**
+     * Creates an authentication request context from the current environmental information.
+     * 
+     * @param loginContext current login context
+     * @param request current request
+     * @param response current response
+     * 
+     * @return created authentication request context
+     */
+    protected ShibbolethSSORequestContext buildRequestContext(ShibbolethSSOLoginContext loginContext,
+            ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) {
+        ShibbolethSSORequestContext requestContext = new ShibbolethSSORequestContext(request, response);
+
+        requestContext.setLoginContext(loginContext);
+
+        requestContext.setPrincipalName(loginContext.getUserID());
+
+        requestContext.setPrincipalAuthenticationMethod(loginContext.getAuthenticationMethod());
+
+        String relyingPartyId = loginContext.getRelyingPartyId();
+
+        requestContext.setRelyingPartyId(relyingPartyId);
+
+        RelyingPartyConfiguration rpConfig = getRelyingPartyConfiguration(relyingPartyId);
+        requestContext.setRelyingPartyConfiguration(rpConfig);
+
+        requestContext.setRelyingPartyRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+        requestContext.setAssertingPartyId(requestContext.getRelyingPartyConfiguration().getProviderId());
+
+        requestContext.setAssertingPartyRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+        requestContext.setProfileConfiguration((ShibbolethSSOConfiguration) rpConfig
+                .getProfileConfiguration(ShibbolethSSOConfiguration.PROFILE_ID));
+
+        return requestContext;
+    }
+
+    /**
+     * Builds the authentication statement for the authenticated principal.
+     * 
+     * @param requestContext current request context
+     * 
+     * @return the created statement
+     */
+    protected AuthenticationStatement buildAuthenticationStatement(ShibbolethSSORequestContext requestContext)
+            throws ProfileException {
+        ShibbolethSSOLoginContext loginContext = requestContext.getLoginContext();
+
+        AuthenticationStatement statement = getAuthenticationStatementBuilder().buildObject();
+        statement.setAuthenticationInstant(loginContext.getAuthenticationInstant());
+        statement.setAuthenticationMethod(loginContext.getAuthenticationMethod());
+
+        // TODO
+        statement.setSubjectLocality(null);
+
+        Subject statementSubject = buildSubject(requestContext, "urn:oasis:names:tc:SAML:1.0:cm:sender-vouches");
+        statement.setSubject(statementSubject);
+
+        return statement;
+    }
+
+    /**
+     * Encodes the request's SAML response and writes it to the servlet response.
+     * 
+     * @param requestContext current request context
+     * 
+     * @throws ProfileException thrown if no message encoder is registered for this profiles binding
+     */
+    protected void encodeResponse(ShibbolethSSORequestContext requestContext) throws ProfileException {
+        if (log.isDebugEnabled()) {
+            log.debug("Encoding response to SAML request from relying party " + requestContext.getRelyingPartyId());
+        }
+        MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(encodingBinding);
+        if (encoder == null) {
+            throw new ProfileException("No response encoder was registered for binding type: " + encodingBinding);
+        }
+
+        super.populateMessageEncoder(encoder);
+        encoder.setResponse(requestContext.getProfileResponse().getRawResponse());
+        encoder.setSamlMessage(requestContext.getSamlResponse());
+        requestContext.setMessageEncoder(encoder);
+
+        try {
+            encoder.encode();
+        } catch (BindingException e) {
+            throw new ProfileException("Unable to encode response to relying party: "
+                    + requestContext.getRelyingPartyId(), e);
+        }
+    }
+
+    /** Represents the internal state of a Shibboleth SSO Request while it's being processed by the IdP. */
+    protected class ShibbolethSSORequestContext extends
+            SAML1ProfileRequestContext<SAMLObject, Response, ShibbolethSSOConfiguration> {
+
+        /** Current login context. */
+        private ShibbolethSSOLoginContext loginContext;
+
+        /**
+         * Constructor.
+         * 
+         * @param request current profile request
+         * @param response current profile response
+         */
+        public ShibbolethSSORequestContext(ProfileRequest<ServletRequest> request,
+                ProfileResponse<ServletResponse> response) {
+            super(request, response);
+        }
+
+        /**
+         * Gets the current login context.
+         * 
+         * @return current login context
+         */
+        public ShibbolethSSOLoginContext getLoginContext() {
+            return loginContext;
+        }
+
+        /**
+         * Sets the current login context.
+         * 
+         * @param context current login context
+         */
+        public void setLoginContext(ShibbolethSSOLoginContext context) {
+            loginContext = context;
+        }
+    }
+}
\ No newline at end of file
index 9c0b720..33ee424 100644 (file)
@@ -80,9 +80,7 @@ import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandle
 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
 import edu.internet2.middleware.shibboleth.idp.session.Session;
 
-/**
- * Common implementation details for profile handlers.
- */
+/** Common implementation details for profile handlers. */
 public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHandler {
 
     /** SAML Version for this profile handler. */
@@ -446,11 +444,6 @@ public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHan
         AbstractSAML2ProfileConfiguration profileConfiguration = requestContext.getProfileConfiguration();
         SAML2AttributeAuthority attributeAuthority = profileConfiguration.getAttributeAuthority();
 
-        if (log.isDebugEnabled()) {
-            log.debug("Resolving principal name for subject of SAML request " + requestContext.getSamlRequest().getID()
-                    + " from relying party " + requestContext.getRelyingPartyId());
-        }
-
         try {
             if (log.isDebugEnabled()) {
                 log.debug("Resolving attributes for principal " + requestContext.getPrincipalName()
index 01d9ce1..7a0dd8f 100644 (file)
@@ -42,9 +42,7 @@ import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.AttributeQueryConfiguration;
 
-/**
- * SAML 2.0 Attribute Query profile handler.
- */
+/** SAML 2.0 Attribute Query profile handler. */
 public class AttributeQueryProfileHandler extends AbstractSAML2ProfileHandler {
 
     /** Class logger. */
@@ -67,6 +65,9 @@ public class AttributeQueryProfileHandler extends AbstractSAML2ProfileHandler {
         Response samlResponse;
         try {
             decodeRequest(requestContext);
+            
+            // Resolve attribute query name id to principal name and place in context
+            resolvePrincipal(requestContext);
 
             // Lookup principal name and attributes, create attribute statement from information
             ArrayList<Statement> statements = new ArrayList<Statement>();
index 634c210..532f9f2 100644 (file)
@@ -56,9 +56,7 @@ import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml2.SS
 import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
 import edu.internet2.middleware.shibboleth.idp.authn.Saml2LoginContext;
 
-/**
- * SAML 2.0 authentication request profile handler.
- */
+/** SAML 2.0 SSO request profile handler. */
 public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
 
     /** Class logger. */
@@ -113,10 +111,46 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
         authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory().getBuilder(
                 AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
     }
+    
+    /**
+     * Convenience method for getting the SAML 2 AuthnStatement builder.
+     * 
+     * @return SAML 2 AuthnStatement builder
+     */
+    public SAMLObjectBuilder<AuthnStatement> getAuthnStatementBuilder(){
+        return authnStatementBuilder;
+    }
+    
+    /**
+     * Convenience method for getting the SAML 2 AuthnContext builder.
+     * 
+     * @return SAML 2 AuthnContext builder
+     */
+    public SAMLObjectBuilder<AuthnContext> getAuthnContextBuilder(){
+        return authnContextBuilder;
+    }
+    
+    /**
+     * Convenience method for getting the SAML 2 AuthnContextClassRef builder.
+     * 
+     * @return SAML 2 AuthnContextClassRef builder
+     */
+    public SAMLObjectBuilder<AuthnContextClassRef> getAuthnContextClassRefBuilder(){
+        return authnContextClassRefBuilder;
+    }
+    
+    /**
+     * Convenience method for getting the SAML 2 AuthnContextDeclRef builder.
+     * 
+     * @return SAML 2 AuthnContextDeclRef builder
+     */
+    public SAMLObjectBuilder<AuthnContextDeclRef> getAuthnContextDeclRefBuilder(){
+        return authnContextDeclRefBuilder;
+    }
 
     /** {@inheritDoc} */
     public String getProfileId() {
-        return "urn:mace:shibboleth:2.0:idp:profiles:saml2:request:authentication";
+        return "urn:mace:shibboleth:2.0:idp:profiles:saml2:request:sso";
     }
 
     /** {@inheritDoc} */
@@ -154,6 +188,7 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
             authnRequest = (AuthnRequest) decoder.getSAMLMessage();
 
             Saml2LoginContext loginContext = new Saml2LoginContext(relyingParty, authnRequest);
+            loginContext.setAuthenticationManagerURL(authenticationManagerPath);
             loginContext.setProfileHandlerURL(httpRequest.getRequestURI());
 
             HttpSession httpSession = httpRequest.getSession();
@@ -187,8 +222,11 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
             ProfileResponse<ServletResponse> response) throws ProfileException {
 
         HttpSession httpSession = ((HttpServletRequest) request.getRawRequest()).getSession(true);
+        
         Saml2LoginContext loginContext = (Saml2LoginContext) httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-        AuthenticationRequestContext requestContext = buildRequestContext(loginContext, request, response);
+        httpSession.removeAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+        
+        SSORequestContext requestContext = buildRequestContext(loginContext, request, response);
 
         Response samlResponse;
         try {
@@ -256,9 +294,9 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
      * 
      * @throws ProfileException thrown if there is a problem creating the context
      */
-    protected AuthenticationRequestContext buildRequestContext(Saml2LoginContext loginContext,
+    protected SSORequestContext buildRequestContext(Saml2LoginContext loginContext,
             ProfileRequest<ServletRequest> request, ProfileResponse<ServletResponse> response) throws ProfileException {
-        AuthenticationRequestContext requestContext = new AuthenticationRequestContext(request, response);
+        SSORequestContext requestContext = new SSORequestContext(request, response);
 
         try {
             String relyingPartyId = loginContext.getRelyingPartyId();
@@ -296,12 +334,12 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
      * 
      * @return constructed authentication statement
      */
-    protected AuthnStatement buildAuthnStatement(AuthenticationRequestContext requestContext) {
+    protected AuthnStatement buildAuthnStatement(SSORequestContext requestContext) {
         Saml2LoginContext loginContext = requestContext.getLoginContext();
 
         AuthnContext authnContext = buildAuthnContext(requestContext);
 
-        AuthnStatement statement = authnStatementBuilder.buildObject();
+        AuthnStatement statement = getAuthnStatementBuilder().buildObject();
         statement.setAuthnContext(authnContext);
         statement.setAuthnInstant(loginContext.getAuthenticationInstant());
 
@@ -326,8 +364,8 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
      * 
      * @return the built authn context
      */
-    protected AuthnContext buildAuthnContext(AuthenticationRequestContext requestContext) {
-        AuthnContext authnContext = authnContextBuilder.buildObject();
+    protected AuthnContext buildAuthnContext(SSORequestContext requestContext) {
+        AuthnContext authnContext = getAuthnContextBuilder().buildObject();
 
         Saml2LoginContext loginContext = requestContext.getLoginContext();
         AuthnRequest authnRequest = requestContext.getSamlRequest();
@@ -336,7 +374,7 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
             if (requestedAuthnContext.getAuthnContextClassRefs() != null) {
                 for (AuthnContextClassRef classRef : requestedAuthnContext.getAuthnContextClassRefs()) {
                     if (classRef.getAuthnContextClassRef().equals(loginContext.getAuthenticationMethod())) {
-                        AuthnContextClassRef ref = authnContextClassRefBuilder.buildObject();
+                        AuthnContextClassRef ref = getAuthnContextClassRefBuilder().buildObject();
                         ref.setAuthnContextClassRef(loginContext.getAuthenticationMethod());
                         authnContext.setAuthnContextClassRef(ref);
                     }
@@ -344,14 +382,14 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
             } else if (requestedAuthnContext.getAuthnContextDeclRefs() != null) {
                 for (AuthnContextDeclRef declRef : requestedAuthnContext.getAuthnContextDeclRefs()) {
                     if (declRef.getAuthnContextDeclRef().equals(loginContext.getAuthenticationMethod())) {
-                        AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
+                        AuthnContextDeclRef ref = getAuthnContextDeclRefBuilder().buildObject();
                         ref.setAuthnContextDeclRef(loginContext.getAuthenticationMethod());
                         authnContext.setAuthnContextDeclRef(ref);
                     }
                 }
             }
         } else {
-            AuthnContextDeclRef ref = authnContextDeclRefBuilder.buildObject();
+            AuthnContextDeclRef ref = getAuthnContextDeclRefBuilder().buildObject();
             ref.setAuthnContextDeclRef(loginContext.getAuthenticationMethod());
             authnContext.setAuthnContextDeclRef(ref);
         }
@@ -366,7 +404,7 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
      * 
      * @throws ProfileException thrown if no message encoder is registered for this profiles binding
      */
-    protected void encodeResponse(AuthenticationRequestContext requestContext) throws ProfileException {
+    protected void encodeResponse(SSORequestContext requestContext) throws ProfileException {
         if (log.isDebugEnabled()) {
             log.debug("Encoding response to SAML request " + requestContext.getSamlRequest().getID()
                     + " from relying party " + requestContext.getRelyingPartyId());
@@ -390,10 +428,8 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
         }
     }
 
-    /**
-     * Represents the internal state of a SAML 2.0 Authentiation Request while it's being processed by the IdP.
-     */
-    protected class AuthenticationRequestContext extends
+    /** Represents the internal state of a SAML 2.0 SSO Request while it's being processed by the IdP. */
+    protected class SSORequestContext extends
             SAML2ProfileRequestContext<AuthnRequest, Response, SSOConfiguration> {
 
         /** Current login context. */
@@ -405,7 +441,7 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
          * @param request current profile request
          * @param response current profile response
          */
-        public AuthenticationRequestContext(ProfileRequest<ServletRequest> request,
+        public SSORequestContext(ProfileRequest<ServletRequest> request,
                 ProfileResponse<ServletResponse> response) {
             super(request, response);
         }