Add explicit PreviousSession support
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 19 Feb 2008 08:25:35 +0000 (08:25 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 19 Feb 2008 08:25:35 +0000 (08:25 +0000)
Cleanup some authn engine code

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

resources/classpath/schema/shibboleth-2.0-idp-profile-handler.xsd
resources/conf/handler.xml
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java
src/edu/internet2/middleware/shibboleth/idp/authn/provider/PreviousSessionLoginHandler.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/config/profile/ProfileHandlerNamespaceHandler.java
src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/AbstractLoginHandlerFactoryBean.java
src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerBeanDefinitionParser.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerFactoryBean.java [new file with mode: 0644]

index f7c0502..c1e0335 100644 (file)
             <xsd:extension base="ShibbolethProfileHandlerType" />
         </xsd:complexContent>
     </xsd:complexType>
+    
+    <xsd:complexType name="PreviousSession">
+        <xsd:complexContent>
+            <xsd:extension base="LoginHandlerType">
+                <xsd:attribute name="servletPath" type="xsd:string">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            Optional servlet path to which the browser may be redirected.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="reportPreviousSessionAuthnMethod" type="xsd:boolean" default="false">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            Whether this login handler should report its authentication method as PreviousSession 
+                            or the authentication method requested by the peer.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+                <xsd:attribute name="supportsPassiveAuthentication" type="xsd:boolean" default="false">
+                    <xsd:annotation>
+                        <xsd:documentation>
+                            Whether this login handler, when redirecting to a servlet, support passives authentication.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                </xsd:attribute>
+            </xsd:extension>
+        </xsd:complexContent>
+    </xsd:complexType>
 
     <xsd:complexType name="RemoteUser">
         <xsd:complexContent>
index 43858cc..e95d972 100644 (file)
                   jaasConfigurationLocation="file://$IDP_HOME$/conf/login.config">
         <AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthenticationMethod>
     </LoginHandler>
+    
+    <!-- 
+        Removal of this login handler will disable SSO support, that is it will require the user to authenticate 
+        on every request.
+    -->
+    <LoginHandler xsi:type="PreviousSession">
+        <AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession</AuthenticationMethod>
+    </LoginHandler>
 
 </ProfileHandlerGroup>
index 9763b1e..b289189 100644 (file)
@@ -18,7 +18,6 @@ package edu.internet2.middleware.shibboleth.idp.authn;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -41,6 +40,7 @@ import org.slf4j.LoggerFactory;
 
 import edu.internet2.middleware.shibboleth.common.session.SessionManager;
 import edu.internet2.middleware.shibboleth.common.util.HttpHelper;
+import edu.internet2.middleware.shibboleth.idp.authn.provider.PreviousSessionLoginHandler;
 import edu.internet2.middleware.shibboleth.idp.profile.IdPProfileHandlerManager;
 import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
@@ -165,7 +165,7 @@ public class AuthenticationEngine extends HttpServlet {
         if (!loginContext.getAuthenticationAttempted()) {
             startUserAuthentication(loginContext, httpRequest, httpResponse);
         } else {
-            completeAuthenticationWithoutActiveMethod(loginContext, httpRequest, httpResponse);
+            completeAuthentication(loginContext, httpRequest, httpResponse);
         }
     }
 
@@ -182,40 +182,28 @@ public class AuthenticationEngine extends HttpServlet {
             HttpServletResponse httpResponse) {
         LOG.debug("Beginning user authentication process");
         try {
+            Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
             Map<String, LoginHandler> possibleLoginHandlers = determinePossibleLoginHandlers(loginContext);
-            ArrayList<AuthenticationMethodInformation> activeAuthnMethods = new ArrayList<AuthenticationMethodInformation>();
-
-            Session userSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
-            if (userSession != null) {
-                activeAuthnMethods.addAll(userSession.getAuthenticationMethods().values());
-            }
 
+            // Filter out possible candidate login handlers by forced and passive authentication requirements
             if (loginContext.isForceAuthRequired()) {
-                LOG.debug("Forced authentication is required, filtering possible login handlers accordingly");
-                filterByForceAuthentication(loginContext, activeAuthnMethods, possibleLoginHandlers);
-            } else {
-                LOG.debug("Forced authentication not required, trying existing authentication methods");
-                for (AuthenticationMethodInformation activeAuthnMethod : activeAuthnMethods) {
-                    if (possibleLoginHandlers.containsKey(activeAuthnMethod.getAuthenticationMethod())) {
-                        completeAuthenticationWithActiveMethod(loginContext, activeAuthnMethod, httpRequest,
-                                httpResponse);
-                        return;
-                    }
-                }
-                LOG.debug("No existing authentication method meets service provides requirements");
+                filterByForceAuthentication(idpSession, loginContext, possibleLoginHandlers);
             }
 
             if (loginContext.isPassiveAuthRequired()) {
-                LOG.debug("Passive authentication is required, filtering poassibl login handlers accordingly.");
                 filterByPassiveAuthentication(loginContext, possibleLoginHandlers);
             }
 
-            // Since we made it this far, just pick the first remaining login handler from the list
-            Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
-            LOG.debug("Authenticating user with login handler of type {}", chosenLoginHandler.getValue().getClass()
-                    .getName());
-            authenticateUser(chosenLoginHandler.getKey(), chosenLoginHandler.getValue(), loginContext, httpRequest,
-                    httpResponse);
+            // If the user already has a session and its usage is acceptable than use it
+            // otherwise just use the first candidate login handler
+            if (idpSession != null
+                    && possibleLoginHandlers.containsKey(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD)) {
+                authenticateUserWithPreviousSession(loginContext, possibleLoginHandlers, httpRequest, httpResponse);
+            } else {
+                Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
+                authenticateUser(chosenLoginHandler.getKey(), chosenLoginHandler.getValue(), loginContext, httpRequest,
+                        httpResponse);
+            }
         } catch (AuthenticationException e) {
             loginContext.setAuthenticationFailure(e);
             returnToProfileHandler(loginContext, httpRequest, httpResponse);
@@ -243,7 +231,8 @@ public class AuthenticationEngine extends HttpServlet {
         Entry<String, LoginHandler> supportedLoginHandler;
         while (supportedLoginHandlerItr.hasNext()) {
             supportedLoginHandler = supportedLoginHandlerItr.next();
-            if (!loginContext.getRequestedAuthenticationMethods().contains(supportedLoginHandler.getKey())) {
+            if (supportedLoginHandler.getKey().equals(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD)
+                    || !loginContext.getRequestedAuthenticationMethods().contains(supportedLoginHandler.getKey())) {
                 supportedLoginHandlerItr.remove();
                 continue;
             }
@@ -261,22 +250,27 @@ public class AuthenticationEngine extends HttpServlet {
     /**
      * Filters out any login handler based on the requirement for forced authentication.
      * 
-     * During forced authentication any handler that has not previously been used to authenticate the the user or any
+     * During forced authentication any handler that has not previously been used to authenticate the user or any
      * handlers that have been and support force re-authentication may be used. Filter out any of the other ones.
      * 
+     * @param idpSession user's current IdP session
      * @param loginContext current login context
-     * @param activeAuthnMethods currently active authentication methods, never null
      * @param loginHandlers login handlers to filter
      * 
      * @throws ForceAuthenticationException thrown if no handlers remain after filtering
      */
-    protected void filterByForceAuthentication(LoginContext loginContext,
-            Collection<AuthenticationMethodInformation> activeAuthnMethods, Map<String, LoginHandler> loginHandlers)
-            throws ForceAuthenticationException {
+    protected void filterByForceAuthentication(Session idpSession, LoginContext loginContext,
+            Map<String, LoginHandler> loginHandlers) throws ForceAuthenticationException {
+        LOG.debug("Forced authentication is required, filtering possible login handlers accordingly");
+
+        ArrayList<AuthenticationMethodInformation> activeMethods = new ArrayList<AuthenticationMethodInformation>();
+        if (idpSession != null) {
+            activeMethods.addAll(idpSession.getAuthenticationMethods().values());
+        }
 
         LoginHandler loginHandler;
-        for (AuthenticationMethodInformation activeAuthnMethod : activeAuthnMethods) {
-            loginHandler = loginHandlers.get(activeAuthnMethod.getAuthenticationMethod());
+        for (AuthenticationMethodInformation activeMethod : activeMethods) {
+            loginHandler = loginHandlers.get(activeMethod.getAuthenticationMethod());
             if (loginHandler != null && !loginHandler.supportsForceAuthentication()) {
                 for (String handlerSupportedMethods : loginHandler.getSupportedAuthenticationMethods()) {
                     loginHandlers.remove(handlerSupportedMethods);
@@ -301,6 +295,8 @@ public class AuthenticationEngine extends HttpServlet {
      */
     protected void filterByPassiveAuthentication(LoginContext loginContext, Map<String, LoginHandler> loginHandlers)
             throws PassiveAuthenticationException {
+        LOG.debug("Passive authentication is required, filtering poassible login handlers accordingly.");
+
         LoginHandler loginHandler;
         Iterator<Entry<String, LoginHandler>> authnMethodItr = loginHandlers.entrySet().iterator();
         while (authnMethodItr.hasNext()) {
@@ -317,56 +313,69 @@ public class AuthenticationEngine extends HttpServlet {
     }
 
     /**
-     * Authenticates the user with the given authentication method provided by the given login handler.
+     * Completes the authentication request using an existing, active, authentication method for the current user.
      * 
-     * @param authnMethod the authentication method that will be used to authenticate the user
-     * @param logingHandler login handler that will authenticate user
      * @param loginContext current login context
+     * @param possibleLoginHandlers login handlers that meet the peers authentication requirements
      * @param httpRequest current HTTP request
      * @param httpResponse current HTTP response
      */
-    protected void authenticateUser(String authnMethod, LoginHandler logingHandler, LoginContext loginContext,
-            HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+    protected void authenticateUserWithPreviousSession(LoginContext loginContext,
+            Map<String, LoginHandler> possibleLoginHandlers, HttpServletRequest httpRequest,
+            HttpServletResponse httpResponse) {
+        LOG.debug("Authenticating user by way of existing session.");
+
+        Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+        PreviousSessionLoginHandler loginHandler = (PreviousSessionLoginHandler) handlerManager.getLoginHandlers().get(
+                PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD);
+
+        AuthenticationMethodInformation authenticationMethod = null;
+        for (String possibleAuthnMethod : possibleLoginHandlers.keySet()) {
+            authenticationMethod = idpSession.getAuthenticationMethods().get(possibleAuthnMethod);
+            if (authenticationMethod != null) {
+                break;
+            }
+        }
+
+        if (loginHandler.reportPreviousSessionAuthnMethod()) {
+            loginContext.setAuthenticationDuration(loginHandler.getAuthenticationDuration());
+            loginContext.setAuthenticationInstant(new DateTime());
+            loginContext.setAuthenticationMethod(PreviousSessionLoginHandler.PREVIOUS_SESSION_AUTHN_METHOD);
+        } else {
+            loginContext.setAuthenticationDuration(authenticationMethod.getAuthenticationDuration());
+            loginContext.setAuthenticationInstant(authenticationMethod.getAuthenticationInstant());
+            loginContext.setAuthenticationMethod(authenticationMethod.getAuthenticationMethod());
+        }
+        loginContext.setPrincipalName(idpSession.getPrincipalName());
 
-        loginContext.setAuthenticationAttempted();
-        loginContext.setAuthenticationDuration(logingHandler.getAuthenticationDuration());
-        loginContext.setAuthenticationMethod(authnMethod);
-        loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
         httpRequest.getSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
-        logingHandler.login(httpRequest, httpResponse);
+        loginHandler.login(httpRequest, httpResponse);
     }
 
     /**
-     * Completes the authentication request using an existing, active, authentication method for the current user.
+     * Authenticates the user with the given authentication method provided by the given login handler.
      * 
+     * @param authnMethod the authentication method that will be used to authenticate the user
+     * @param loginHandler login handler that will authenticate user
      * @param loginContext current login context
-     * @param authenticationMethod authentication method to use to complete the request
      * @param httpRequest current HTTP request
      * @param httpResponse current HTTP response
      */
-    protected void completeAuthenticationWithActiveMethod(LoginContext loginContext,
-            AuthenticationMethodInformation authenticationMethod, HttpServletRequest httpRequest,
-            HttpServletResponse httpResponse) {
-        Session shibSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
-
-        loginContext.setAuthenticationDuration(authenticationMethod.getAuthenticationDuration());
-        loginContext.setAuthenticationInstant(authenticationMethod.getAuthenticationInstant());
-        loginContext.setAuthenticationMethod(authenticationMethod.getAuthenticationMethod());
-        loginContext.setPrincipalAuthenticated(true);
-        loginContext.setPrincipalName(shibSession.getPrincipalName());
-
-        ServiceInformation serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(),
-                authenticationMethod);
-        shibSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
+    protected void authenticateUser(String authnMethod, LoginHandler loginHandler, LoginContext loginContext,
+            HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+        LOG.debug("Authenticating user with login handler of type {}", loginHandler.getClass().getName());
 
-        LOG.debug("Treating user {} as authenticated via existing method {}", loginContext.getPrincipalName(),
-                loginContext.getAuthenticationMethod());
-        returnToProfileHandler(loginContext, httpRequest, httpResponse);
+        loginContext.setAuthenticationAttempted();
+        loginContext.setAuthenticationInstant(new DateTime());
+        loginContext.setAuthenticationDuration(loginHandler.getAuthenticationDuration());
+        loginContext.setAuthenticationMethod(authnMethod);
+        loginContext.setAuthenticationEngineURL(HttpHelper.getRequestUriWithoutContext(httpRequest));
+        httpRequest.getSession().setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+        loginHandler.login(httpRequest, httpResponse);
     }
 
     /**
-     * Completes the authentication process when and already active authentication mechanism wasn't used, that is, when
-     * the user was really authenticated.
+     * Completes the authentication process.
      * 
      * The principal name set by the authentication handler is retrieved and pushed in to the login context, a
      * Shibboleth session is created if needed, information indicating that the user has logged into the service is
@@ -376,25 +385,28 @@ public class AuthenticationEngine extends HttpServlet {
      * @param httpRequest current HTTP request
      * @param httpResponse current HTTP response
      */
-    protected void completeAuthenticationWithoutActiveMethod(LoginContext loginContext, HttpServletRequest httpRequest,
+    protected void completeAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
             HttpServletResponse httpResponse) {
 
-        String principalName = DatatypeHelper.safeTrimOrNullString((String) httpRequest
-                .getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
+        // We check if the principal name was already set in the login context
+        // if not attempt to pull it from where login handlers are supposed to provide it
+        String principalName = loginContext.getPrincipalName();
         if (principalName == null) {
-            loginContext.setPrincipalAuthenticated(false);
-            loginContext.setAuthenticationFailure(new AuthenticationException(
-                    "No principal name returned from authentication handler."));
-            LOG.error("No principal name returned from authentication method: "
-                    + loginContext.getAuthenticationMethod());
-            returnToProfileHandler(loginContext, httpRequest, httpResponse);
-            return;
+            DatatypeHelper.safeTrimOrNullString((String) httpRequest.getAttribute(LoginHandler.PRINCIPAL_NAME_KEY));
+            if (principalName != null) {
+                loginContext.setPrincipalName(principalName);
+            }else{
+                loginContext.setPrincipalAuthenticated(false);
+                loginContext.setAuthenticationFailure(new AuthenticationException(
+                        "No principal name returned from authentication handler."));
+                LOG.error("No principal name returned from authentication method: "
+                        + loginContext.getAuthenticationMethod());
+                returnToProfileHandler(loginContext, httpRequest, httpResponse);
+                return;
+            }
         }
-
         loginContext.setPrincipalAuthenticated(true);
-        loginContext.setPrincipalName(principalName);
-        loginContext.setAuthenticationInstant(new DateTime());
-
+        
         // We allow a login handler to override the authentication method in the event that it supports multiple methods
         String actualAuthnMethod = DatatypeHelper.safeTrimOrNullString((String) httpRequest
                 .getAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY));
@@ -418,12 +430,12 @@ public class AuthenticationEngine extends HttpServlet {
      */
     protected void updateUserSession(LoginContext loginContext, HttpServletRequest httpRequest,
             HttpServletResponse httpResponse) {
-        Session shibSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
-        if (shibSession == null) {
+        Session idpSession = (Session) httpRequest.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+        if (idpSession == null) {
             LOG.debug("Creating shibboleth session for principal {}", loginContext.getPrincipalName());
-            shibSession = (Session) sessionManager.createSession(loginContext.getPrincipalName());
-            loginContext.setSessionID(shibSession.getSessionID());
-            addSessionCookie(httpRequest, httpResponse, shibSession);
+            idpSession = (Session) sessionManager.createSession(loginContext.getPrincipalName());
+            loginContext.setSessionID(idpSession.getSessionID());
+            addSessionCookie(httpRequest, httpResponse, idpSession);
         }
 
         LOG.debug("Recording authentication and service information in Shibboleth session for principal: {}",
@@ -435,13 +447,13 @@ public class AuthenticationEngine extends HttpServlet {
         }
 
         AuthenticationMethodInformation authnMethodInfo = new AuthenticationMethodInformationImpl(subject, authnMethod,
-                new DateTime(), loginContext.getAuthenticationDuration());
+                loginContext.getAuthenticationInstant(), loginContext.getAuthenticationDuration());
 
-        shibSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
+        idpSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
 
         ServiceInformation serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(),
                 authnMethodInfo);
-        shibSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
+        idpSession.getServicesInformation().put(serviceInfo.getEntityID(), serviceInfo);
     }
 
     /**
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/provider/PreviousSessionLoginHandler.java b/src/edu/internet2/middleware/shibboleth/idp/authn/provider/PreviousSessionLoginHandler.java
new file mode 100644 (file)
index 0000000..d0b695c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2008 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.provider;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.util.URLBuilder;
+import org.opensaml.xml.util.DatatypeHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
+
+/**
+ * Login handler that is called when user is logged in under a previously existing session.
+ * 
+ * This login handler can optionally redirect the browser to a given URL. This provides a mechanism for extensions to
+ * hook into the authentication process on every request. If this option is used and the servlet to which the browser is
+ * redirected does not take visible control of the request be sure to indicate passive authentication support by means
+ * of {@link PreviousSessionLoginHandler#setSupportsPassive(boolean)}.
+ * 
+ * When the servlet has completed it's work it <strong>MUST</strong> call
+ * {@link AuthenticationEngine#returnToAuthenticationEngine(HttpServletRequest, HttpServletResponse)} in order to
+ * transfer control back to the authentication engine.
+ */
+public class PreviousSessionLoginHandler extends AbstractLoginHandler {
+
+    /** PreviousSession authentication method URI. */
+    public static final String PREVIOUS_SESSION_AUTHN_METHOD = "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession";
+
+    /** Class logger. */
+    private final Logger log = LoggerFactory.getLogger(PreviousSessionLoginHandler.class);
+
+    /** The path of the servlet to which the user agent may be redirected. */
+    private String servletPath;
+
+    /** Whether to report the authentication method as PreviousSession. */
+    private boolean reportPreviousSessionAuthnMethod;
+
+    /** Constructor. */
+    public PreviousSessionLoginHandler() {
+        super();
+        servletPath = null;
+    }
+
+    /**
+     * Get the path of the servlet to which the user agent may be redirected.
+     * 
+     * @return path of the servlet to which the user agent may be redirected
+     */
+    public String getServletPath() {
+        return servletPath;
+    }
+
+    /**
+     * Set the path of the servlet to which the user agent may be redirected.
+     * 
+     * @param path path of the servlet to which the user agent may be redirected
+     */
+    public void setServletPath(String path) {
+        servletPath = DatatypeHelper.safeTrimOrNullString(path);
+    }
+
+    /**
+     * Gets whether to use PreviousSession as the users authentication method.
+     * 
+     * @return whether to use PreviousSession as the users authentication method
+     */
+    public boolean reportPreviousSessionAuthnMethod() {
+        return reportPreviousSessionAuthnMethod;
+    }
+
+    /**
+     * Sets whether to use PreviousSession as the users authentication method.
+     * 
+     * @param report whether to use PreviousSession as the users authentication method
+     */
+    public void setReportPreviousSessionAuthnMethod(boolean report) {
+        reportPreviousSessionAuthnMethod = report;
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsPassive() {
+        if (servletPath == null) {
+            return true;
+        }
+
+        return super.supportsPassive();
+    }
+
+    /** {@inheritDoc} */
+    public void login(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+        if (servletPath == null) {
+            AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse);
+        } else {
+            try {
+                StringBuilder pathBuilder = new StringBuilder();
+                pathBuilder.append(httpRequest.getContextPath());
+                if (!servletPath.startsWith("/")) {
+                    pathBuilder.append("/");
+                }
+                pathBuilder.append(servletPath);
+
+                URLBuilder urlBuilder = new URLBuilder();
+                urlBuilder.setScheme(httpRequest.getScheme());
+                urlBuilder.setHost(httpRequest.getLocalName());
+                urlBuilder.setPort(httpRequest.getLocalPort());
+                urlBuilder.setPath(pathBuilder.toString());
+
+                log.debug("Redirecting to {}", urlBuilder.buildURL());
+                httpResponse.sendRedirect(urlBuilder.buildURL());
+                return;
+            } catch (IOException ex) {
+                log.error("Unable to redirect to previous session authentication servlet.", ex);
+            }
+        }
+    }
+}
\ No newline at end of file
index 7249c82..a650933 100644 (file)
@@ -21,6 +21,7 @@ import javax.xml.namespace.QName;
 import edu.internet2.middleware.shibboleth.common.config.BaseSpringNamespaceHandler;
 import edu.internet2.middleware.shibboleth.common.config.profile.JSPErrorHandlerBeanDefinitionParser;
 import edu.internet2.middleware.shibboleth.common.config.profile.VelocityErrorHandlerBeanDefinitionParser;
+import edu.internet2.middleware.shibboleth.idp.config.profile.authn.PreviousSessionLoginHandlerBeanDefinitionParser;
 import edu.internet2.middleware.shibboleth.idp.config.profile.authn.RemoteUserLoginHandlerBeanDefinitionParser;
 import edu.internet2.middleware.shibboleth.idp.config.profile.authn.UsernamePasswordLoginHandlerBeanDefinitionParser;
 import edu.internet2.middleware.shibboleth.idp.config.profile.saml1.SAML1ArtifactResolutionProfileHanderBeanDefinitionParser;
@@ -45,7 +46,7 @@ public class ProfileHandlerNamespaceHandler extends BaseSpringNamespaceHandler {
 
         registerBeanDefinitionParser(ProfileHandlerGroupBeanDefinitionParser.SCHEMA_TYPE,
                 new ProfileHandlerGroupBeanDefinitionParser());
-        
+
         registerBeanDefinitionParser(StatusHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new StatusHandlerBeanDefinitionParser());
 
@@ -60,19 +61,22 @@ public class ProfileHandlerNamespaceHandler extends BaseSpringNamespaceHandler {
 
         registerBeanDefinitionParser(SAML1AttributeQueryProfileHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new SAML1AttributeQueryProfileHandlerBeanDefinitionParser());
-        
+
         registerBeanDefinitionParser(SAML1ArtifactResolutionProfileHanderBeanDefinitionParser.SCHEMA_TYPE,
                 new SAML1ArtifactResolutionProfileHanderBeanDefinitionParser());
 
         registerBeanDefinitionParser(SAML2SSOProfileHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new SAML2SSOProfileHandlerBeanDefinitionParser());
-        
+
         registerBeanDefinitionParser(SAML2AttributeQueryProfileHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new SAML2AttributeQueryProfileHandlerBeanDefinitionParser());
-        
+
         registerBeanDefinitionParser(SAML2ArtifactResolutionProfileHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new SAML2ArtifactResolutionProfileHandlerBeanDefinitionParser());
 
+        registerBeanDefinitionParser(PreviousSessionLoginHandlerBeanDefinitionParser.SCHEMA_TYPE,
+                new PreviousSessionLoginHandlerBeanDefinitionParser());
+
         registerBeanDefinitionParser(RemoteUserLoginHandlerBeanDefinitionParser.SCHEMA_TYPE,
                 new RemoteUserLoginHandlerBeanDefinitionParser());
 
index 57e7477..d04bb4c 100644 (file)
@@ -70,7 +70,7 @@ public abstract class AbstractLoginHandlerFactoryBean extends AbstractFactoryBea
     }
 
     /**
-     * Populates the authenication duration and methods of the handler.
+     * Populates the authentication duration and methods of the handler.
      * 
      * @param handler the authentication handler to populate
      */
diff --git a/src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerBeanDefinitionParser.java b/src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerBeanDefinitionParser.java
new file mode 100644 (file)
index 0000000..6b89bfc
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 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.config.profile.authn;
+
+import javax.xml.namespace.QName;
+
+import org.opensaml.xml.util.DatatypeHelper;
+import org.opensaml.xml.util.XMLHelper;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.w3c.dom.Element;
+
+import edu.internet2.middleware.shibboleth.idp.config.profile.ProfileHandlerNamespaceHandler;
+
+/**
+ * Spring bean definition parser for previous session authentication handlers.
+ */
+public class PreviousSessionLoginHandlerBeanDefinitionParser extends AbstractLoginHandlerBeanDefinitionParser {
+
+    /** Schema type. */
+    public static final QName SCHEMA_TYPE = new QName(ProfileHandlerNamespaceHandler.NAMESPACE, "PreviousSession");
+
+    /** {@inheritDoc} */
+    protected Class getBeanClass(Element arg0) {
+        return PreviousSessionLoginHandlerFactoryBean.class;
+    }
+
+    /** {@inheritDoc} */
+    protected void doParse(Element config, BeanDefinitionBuilder builder) {
+        super.doParse(config, builder);
+
+        builder.addPropertyValue("servletPath", DatatypeHelper.safeTrimOrNullString(config.getAttributeNS(null,
+                "servletPath")));
+
+        builder.addPropertyValue("supportsPassiveAuth", XMLHelper.getAttributeValueAsBoolean(config.getAttributeNodeNS(
+                null, "supportsPassiveAuthentication")));
+
+        builder.addPropertyValue("reportPreviousSessionAuthnMethod", XMLHelper.getAttributeValueAsBoolean(config
+                .getAttributeNodeNS(null, "reportPreviousSessionAuthnMethod")));
+    }
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerFactoryBean.java b/src/edu/internet2/middleware/shibboleth/idp/config/profile/authn/PreviousSessionLoginHandlerFactoryBean.java
new file mode 100644 (file)
index 0000000..e3f3e79
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2008 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.config.profile.authn;
+
+import edu.internet2.middleware.shibboleth.idp.authn.provider.PreviousSessionLoginHandler;
+
+/**
+ * Spring factory for {@link PreviousSessionLoginHandler}.
+ */
+public class PreviousSessionLoginHandlerFactoryBean extends AbstractLoginHandlerFactoryBean {
+
+    /** Path to protected servlet. */
+    private String servletPath;
+
+    /** Whether the login handler supports passive authentication. */
+    private boolean supportPassiveAuth;
+
+    /** Whether the login handler will report its authentication method as PreviousSession. */
+    private boolean reportPreviousSessionAuthnMethod;
+
+    /** {@inheritDoc} */
+    public Class getObjectType() {
+        return PreviousSessionLoginHandler.class;
+    }
+
+    /**
+     * Gets the path of the servlet to which the user agent may be redirected.
+     * 
+     * @return path of the servlet to which the user agent may be redirected
+     */
+    public String getServletPath() {
+        return servletPath;
+    }
+
+    /**
+     * Sets the path of the servlet to which the user agent may be redirected.
+     * 
+     * @param path path of the servlet to which the user agent may be redirected
+     */
+    public void setServletPath(String path) {
+        servletPath = path;
+    }
+
+    /**
+     * Gets whether the login handler supports passive authentication.
+     * 
+     * @return whether the login handler supports passive authentication
+     */
+    public boolean supportsPassiveAuth() {
+        return supportPassiveAuth;
+    }
+
+    /**
+     * Sets whether the login handler supports passive authentication.
+     * 
+     * @param supported whether the login handler supports passive authentication
+     */
+    public void setSupportsPassiveAuth(boolean supported) {
+        supportPassiveAuth = supported;
+    }
+
+    /**
+     * Gets whether the login handler will report its authentication method as PreviousSession.
+     * 
+     * @return whether the login handler will report its authentication method as PreviousSession
+     */
+    public boolean reportPreviousSessionAuthnMethod() {
+        return reportPreviousSessionAuthnMethod;
+    }
+
+    /**
+     * Sets whether the login handler will report its authentication method as PreviousSession.
+     * 
+     * @param report whether the login handler will report its authentication method as PreviousSession
+     */
+    public void setReportPreviousSessionAuthnMethod(boolean report) {
+        reportPreviousSessionAuthnMethod = report;
+    }
+
+    /** {@inheritDoc} */
+    protected Object createInstance() throws Exception {
+        PreviousSessionLoginHandler handler = new PreviousSessionLoginHandler();
+        handler.setServletPath(getServletPath());
+        handler.setSupportsPassive(supportsPassiveAuth());
+        handler.setReportPreviousSessionAuthnMethod(reportPreviousSessionAuthnMethod());
+        populateHandler(handler);
+        return handler;
+    }
+}
\ No newline at end of file