Initial rework of authentication code, needs logging and testing
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Thu, 14 Jun 2007 00:29:49 +0000 (00:29 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Thu, 14 Jun 2007 00:29:49 +0000 (00:29 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@2244 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

22 files changed:
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandler.java
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationManager.java [deleted file]
src/edu/internet2/middleware/shibboleth/idp/authn/LoginContext.java
src/edu/internet2/middleware/shibboleth/idp/authn/impl/AbstractAuthenticationHandler.java [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/idp/authn/impl/IPAddressHandler.java
src/edu/internet2/middleware/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
src/edu/internet2/middleware/shibboleth/idp/authn/impl/RemoteUserAuthenticationHandler.java
src/edu/internet2/middleware/shibboleth/idp/authn/impl/UsernamePasswordAuthenticationHandler.java
src/edu/internet2/middleware/shibboleth/idp/authn/impl/UsernamePasswordAuthenticationServlet.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/AbstractSAML1ProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml1/ShibbolethSSOProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/AbstractSAML2ProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/profile/saml2/SSOProfileHandler.java
src/edu/internet2/middleware/shibboleth/idp/session/AuthenticationMethodInformation.java
src/edu/internet2/middleware/shibboleth/idp/session/ServiceInformation.java
src/edu/internet2/middleware/shibboleth/idp/session/Session.java
src/edu/internet2/middleware/shibboleth/idp/session/impl/AuthenticationMethodInformationImpl.java
src/edu/internet2/middleware/shibboleth/idp/session/impl/ServiceInformationImpl.java
src/edu/internet2/middleware/shibboleth/idp/session/impl/SessionImpl.java
src/edu/internet2/middleware/shibboleth/idp/session/impl/SessionManagerImpl.java

diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java b/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java
new file mode 100644 (file)
index 0000000..4316219
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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.authn;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
+import org.opensaml.xml.util.Pair;
+
+import edu.internet2.middleware.shibboleth.common.profile.ProfileHandlerManager;
+import edu.internet2.middleware.shibboleth.common.session.SessionManager;
+import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
+import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
+import edu.internet2.middleware.shibboleth.idp.session.Session;
+import edu.internet2.middleware.shibboleth.idp.session.impl.AuthenticationMethodInformationImpl;
+import edu.internet2.middleware.shibboleth.idp.session.impl.ServiceInformationImpl;
+
+/**
+ * Manager responsible for handling authentication requests.
+ */
+public class AuthenticationEngine extends HttpServlet {
+
+    /** Class logger. */
+    private static final Logger log = Logger.getLogger(AuthenticationEngine.class);
+
+    /**
+     * Gets the manager used to retrieve handlers for requests.
+     * 
+     * @return manager used to retrieve handlers for requests
+     */
+    public ProfileHandlerManager getProfileHandlerManager() {
+        return (ProfileHandlerManager) getServletContext().getAttribute("handlerManager");
+    }
+
+    /**
+     * Gets the session manager to be used.
+     * 
+     * @return session manager to be used
+     */
+    @SuppressWarnings("unchecked")
+    public SessionManager<Session> getSessionManager() {
+        return (SessionManager<Session>) getServletContext().getAttribute("sessionManager");
+    }
+
+    /**
+     * Gets the authentication handler manager used by this engine.
+     * 
+     * @return authentication handler manager used by this engine
+     */
+    public AuthenticationHandlerManager getAuthenticationHandlerManager() {
+        return (AuthenticationHandlerManager) getServletContext().getAttribute("authenticationHandlerManager");
+    }
+    
+
+    /**
+     * Returns control back to the authentication engine.
+     * 
+     * @param httpRequest current http request
+     * @param httpResponse current http response
+     * @param loginContext user login context
+     */
+    public static void returnToAuthenticationEngine(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+        HttpSession httpSession = httpRequest.getSession();
+
+        LoginContext loginContext = (LoginContext) httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+        
+        try {
+            RequestDispatcher distpather = httpRequest.getRequestDispatcher(loginContext.getAuthenticationManagerURL());
+            distpather.forward(httpRequest, httpResponse);
+        } catch (IOException e) {
+            log.fatal("Unable to return control back to authentication engine", e);
+        } catch (ServletException e) {
+            log.fatal("Unable to return control back to authentication engine", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    protected void service(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException,
+            IOException {
+        HttpSession httpSession = httpRequest.getSession();
+
+        LoginContext loginContext = (LoginContext) httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
+        if (loginContext == null) {
+            // TODO error
+        }
+
+        // If authentication has been attempted, don't try it again.
+        if (loginContext.getAuthenticationAttempted()) {
+            handleNewAuthnRequest(loginContext, httpRequest, httpResponse);
+        } else {
+            finishAuthnRequest(loginContext, httpRequest, httpResponse);
+        }
+    }
+
+    /**
+     * Handle a new authentication request.
+     * 
+     * @param loginContext The {@link LoginContext} for the new authentication request
+     * @param httpRequest The servlet request containing the authn request
+     * @param httpResponse The associated servlet response.
+     * 
+     * @throws IOException thrown if there is a problem reading/writting to the HTTP request/response
+     * @throws ServletException thrown if there is a problem transferring control to the authentication handler
+     */
+    protected void handleNewAuthnRequest(LoginContext loginContext, HttpServletRequest httpRequest,
+            HttpServletResponse httpResponse) throws ServletException, IOException {
+
+        HttpSession httpSession = httpRequest.getSession();
+        String shibSessionId = (String) httpSession.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+        Session shibSession = getSessionManager().getSession(shibSessionId);
+
+        AuthenticationMethodInformation authenticationMethod = getUsableExistingAuthenticationMethod(loginContext,
+                shibSession);
+        if (authenticationMethod != null) {
+            loginContext.setAuthenticationDuration(authenticationMethod.getAuthenticationDuration());
+            loginContext.setAuthenticationInstant(authenticationMethod.getAuthenticationInstant());
+            loginContext.setAuthenticationMethod(authenticationMethod.getAuthenticationMethod());
+            loginContext.setPrincipalAuthenticated(true);
+            loginContext.setPrincipalName(shibSession.getPrincipalName());
+            finishAuthnRequest(loginContext, httpRequest, httpResponse);
+        } else {
+            Pair<String, AuthenticationHandler> handler = getAuthenticationHandlerManager().getAuthenticationHandler(
+                    loginContext);
+
+            if (handler == null) {
+                loginContext.setPassiveAuth(false);
+                loginContext
+                        .setAuthenticationFailureMessage("No installed AuthenticationHandler can satisfy the authentication request.");
+                log.error("No installed AuthenticationHandler can satisfy the authentication request.");
+                finishAuthnRequest(loginContext, httpRequest, httpResponse);
+            }
+
+            loginContext.setAuthenticationAttempted();
+            loginContext.setAuthenticationDuration(handler.getSecond().getAuthenticationDuration());
+            loginContext.setAuthenticationMethod(handler.getFirst());
+            loginContext.setAuthenticationManagerURL(httpRequest.getRequestURI());
+
+            httpSession.setAttribute(LoginContext.LOGIN_CONTEXT_KEY, loginContext);
+            handler.getSecond().login(loginContext, httpRequest, httpResponse);
+        }
+    }
+
+    /**
+     * Gets the authentication method, currently active for the user, that also meets the requirements expressed by the
+     * login context. If a method is returned the user does not need to authenticate again, if null is returned then the
+     * user must be authenticated.
+     * 
+     * @param loginContext user login context
+     * @param shibSession user's shibboleth session
+     * 
+     * @return active authentication method that meets authentication requirements or null
+     */
+    protected AuthenticationMethodInformation getUsableExistingAuthenticationMethod(LoginContext loginContext,
+            Session shibSession) {
+        if (loginContext.getForceAuth() || shibSession == null) {
+            return null;
+        }
+
+        List<String> preferredAuthnMethods = loginContext.getRequestedAuthenticationMethods();
+
+        if (preferredAuthnMethods == null || preferredAuthnMethods.size() == 0) {
+            for (AuthenticationMethodInformation authnMethod : shibSession.getAuthenticationMethods().values()) {
+                if (!authnMethod.isExpired()) {
+                    return authnMethod;
+                }
+            }
+        } else {
+            for (String preferredAuthnMethod : preferredAuthnMethods) {
+                if (shibSession.getAuthenticationMethods().containsKey(preferredAuthnMethod)) {
+                    AuthenticationMethodInformation authnMethodInfo = shibSession.getAuthenticationMethods().get(
+                            preferredAuthnMethod);
+                    if (!authnMethodInfo.isExpired()) {
+                        return authnMethodInfo;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Handle the "return leg" of an authentication request (i.e. clean up after an authentication handler has run).
+     * 
+     * @param loginContext The {@link LoginContext} for the new authentication request
+     * @param httpRequest The servlet request containing the authn request
+     * @param httpResponse The associated servlet response.
+     * 
+     * @throws IOException thrown if there is a problem reading/writting to the HTTP request/response
+     * @throws ServletException thrown if there is a problem transferring control to the authentication profile handler
+     */
+    protected void finishAuthnRequest(LoginContext loginContext, HttpServletRequest httpRequest,
+            HttpServletResponse httpResponse) throws ServletException, IOException {
+
+        HttpSession httpSession = httpRequest.getSession();
+        String shibSessionId = (String) httpSession.getAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE);
+        Session shibSession = null;
+        AuthenticationMethodInformation authnMethodInfo = null;
+        ServiceInformation serviceInfo = null;
+
+        if (!loginContext.getAuthenticationAttempted()) {
+            // Authentication wasn't attempted so we're using a previously established authentication method
+            shibSession = getSessionManager().getSession(shibSessionId);
+            authnMethodInfo = shibSession.getAuthenticationMethods().get(loginContext.getAuthenticationMethod());
+        } else {
+            if (shibSessionId == null) {
+                InetAddress addr;
+                try {
+                    addr = InetAddress.getByName(httpRequest.getRemoteAddr());
+                } catch (UnknownHostException ex) {
+                    addr = null;
+                }
+
+                shibSession = (Session) getSessionManager().createSession(addr, loginContext.getPrincipalName());
+                httpSession.setAttribute(Session.HTTP_SESSION_BINDING_ATTRIBUTE, shibSession.getSessionID());
+
+                authnMethodInfo = new AuthenticationMethodInformationImpl(loginContext.getAuthenticationMethod(),
+                        new DateTime(), loginContext.getAuthenticationDuration());
+                shibSession.getAuthenticationMethods().put(authnMethodInfo.getAuthenticationMethod(), authnMethodInfo);
+            }
+        }
+
+        loginContext.setSessionID(shibSession.getSessionID());
+        shibSession.setLastActivityInstant(new DateTime());
+
+        serviceInfo = shibSession.getServicesInformation().get(loginContext.getRelyingPartyId());
+        if (serviceInfo == null) {
+            serviceInfo = new ServiceInformationImpl(loginContext.getRelyingPartyId(), new DateTime(), authnMethodInfo);
+        }
+
+        RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginContext.getProfileHandlerURL());
+        dispatcher.forward(httpRequest, httpResponse);
+    }
+
+    // TODO logout support
+}
\ No newline at end of file
index 957fd4b..c0ba453 100644 (file)
@@ -20,78 +20,70 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Authentication handlers are responsible for authenticating a user using a
- * particular authentication context class and logging users out for that same
- * mechanism.
+ * Authentication handlers are responsible for authenticating a user using a particular authentication context class and
+ * logging users out for that same mechanism.
  * 
- * When this handler is invoked to log a user in the incoming request will
- * contain a {@link AuthnRequest} attribute registered under the name
- * <strong>AuthnRequest</strong>. If the authentication request coming into the
- * IdP is not a SAML 2 request the receiving profile handler will translate the
- * incoming details into a {@link AuthnRequest}.
+ * When this handler is invoked to log a user in the incoming request will contain a {@link AuthnRequest} attribute
+ * registered under the name <strong>AuthnRequest</strong>. If the authentication request coming into the IdP is not a
+ * SAML 2 request the receiving profile handler will translate the incoming details into a {@link AuthnRequest}.
  * 
- * Upon successfull authentication the handler <strong>must</strong> set a
- * request attribute called <strong>principal</strong> with the principal name
- * of the authenticated user. It must then forward the request/response to the
- * provided return location by means of the
- * {@link javax.servlet.RequestDispatcher.RequestDispatcher#forward(
+ * Upon successfull authentication the handler <strong>must</strong> set a request attribute called <strong>principal</strong>
+ * with the principal name of the authenticated user. It must then forward the request/response to the provided return
+ * location by means of the {@link javax.servlet.RequestDispatcher.RequestDispatcher#forward(
  * javax.servlet.ServletRequest, javax.servlet.ServletResponse)} method.
  * 
- * When this handler is invoked to log a user out of the particular
- * authentication source the handler may perform any operation necessary to log
- * a user out. When finished it must then forward the request/response to the
- * provided return location by means of the
- * {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
- * method. This call will occur before SAML logout requests have been sent to
- * all services supporting such requests.
+ * When this handler is invoked to log a user out of the particular authentication source the handler may perform any
+ * operation necessary to log a user out. When finished it must then forward the request/response to the provided return
+ * location by means of the
+ * {@link RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} method. This call will
+ * occur before SAML logout requests have been sent to all services supporting such requests.
  * 
- * AuthentcationHandlers <strong>MUST NOT</strong> change or add any data to
- * the user's {@link javax.servlet.http.HttpSession} that persists past the
- * process of authenticating the user, that is no additional session data may be
- * added and no existing session data may be changed when the handler redirects
- * back to the return location.
+ * AuthentcationHandlers <strong>MUST NOT</strong> change or add any data to the user's
+ * {@link javax.servlet.http.HttpSession} that persists past the process of authenticating the user, that is no
+ * additional session data may be added and no existing session data may be changed when the handler redirects back to
+ * the return location.
  */
 public interface AuthenticationHandler {
+    
+    /** Request attribute to which user's principal name should be bound. */
+    public static final String PRINCIPAL_NAME_KEY = "principal";
 
-       /**
-        * Authenticates the user making the request.
-        * 
-        * @param request
-        *            user request
-        * @param response
-        *            response to user
-        * @param loginCtx
-        *            The {@link LoginContext} for the reqeust.
-        */
-       public void login(HttpServletRequest request, HttpServletResponse response,
-                       LoginContext loginCtx);
+    /**
+     * Gets the length of time, in milliseconds, after which a user authenticated by this handler should be
+     * re-authenticated.
+     * 
+     * @return length of time, in milliseconds, after which a user should be re-authenticated
+     */
+    public long getAuthenticationDuration();
+    
+    /**
+     * Gets whether this handler supports passive authentication.
+     * 
+     * @return whether this handler supports passive authentication
+     */
+    public boolean supportsPassive();
 
-       /**
-        * Logs out the given user from the authentication mechanism represented by
-        * this handler.
-        * 
-        * @param request
-        *            user request
-        * @param response
-        *            response to user
-        * @param principal
-        *            principal named as returned during authentication
-        */
-       public void logout(HttpServletRequest request,
-                       HttpServletResponse response, String principal);
+    /**
+     * Returns if this handler supports the ability to force a user to (re-)authenticate.
+     * 
+     * @return if this handler can force a user to (re-)authenticate.
+     */
+    public boolean supportsForceAuthentication();
 
-       /**
-        * Gets whether this handler supports passive authentication.
-        * 
-        * @return whether this handler supports passive authentication
-        */
-       public boolean supportsPassive();
+    /**
+     * Authenticates the user making the request.
+     * @param loginContext The {@link LoginContext} for the reqeust.
+     * @param httpRequest user request
+     * @param httpResponse response to user
+     */
+    public void login(LoginContext loginContext, HttpServletRequest httpRequest, HttpServletResponse httpResponse);
 
-       /**
-        * Returns if this handler supports the ability to force a user to
-        * (re-)authenticate.
-        * 
-        * @return if this handler can force a user to (re-)authenticate.
-        */
-       public boolean supportsForceAuthentication();
+    /**
+     * Logs out the given user from the authentication mechanism represented by this handler.
+     * 
+     * @param request user request
+     * @param response response to user
+     * @param principal principal named as returned during authentication
+     */
+    public void logout(HttpServletRequest request, HttpServletResponse response, String principal);
 }
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java b/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationHandlerManager.java
new file mode 100644 (file)
index 0000000..f7053d1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import java.util.Map;
+
+import org.opensaml.xml.util.Pair;
+
+/**
+ * Manager for registering and retrieving authentication handlers.
+ */
+public interface AuthenticationHandlerManager {
+
+    /**
+     * Gets the registered authentication handlers.
+     * 
+     * @return registered authentication handlers
+     */
+    public Map<String, AuthenticationHandler> getAuthenticationHandlers();
+
+    /**
+     * Gets the authentication handler appropriate for the given loging context. The mechanism used to determine the
+     * "appropriate" handler is implementation specific.
+     * 
+     * @param loginContext current login context
+     * 
+     * @return authentication method URI and handler appropriate for given login context
+     */
+    public Pair<String, AuthenticationHandler> getAuthenticationHandler(LoginContext loginContext);
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationManager.java b/src/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationManager.java
deleted file mode 100644 (file)
index d0460e3..0000000
+++ /dev/null
@@ -1,330 +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.authn;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import javolution.util.FastMap;
-
-import org.apache.log4j.Logger;
-
-import edu.internet2.middleware.shibboleth.common.session.SessionManager;
-import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
-import edu.internet2.middleware.shibboleth.idp.session.Session;
-import edu.internet2.middleware.shibboleth.idp.session.impl.AuthenticationMethodInformationImpl;
-
-/**
- * Manager responsible for handling authentication requests.
- */
-//TODO map needed objects into servlet context information and fetch from there
-public class AuthenticationManager extends HttpServlet {
-
-    /** log4j. */
-    private final Logger log = Logger.getLogger(AuthenticationManager.class);
-
-    /** SessionManager to be used. */
-    private SessionManager sessionMgr;
-
-    /** Map of URIs onto AuthenticationHandlerInfo. */
-    private Map<String, AuthenticationHandler> handlerMap = new ConcurrentHashMap<String, AuthenticationHandler>();
-
-    /** The default AuthenticationHandler. */
-    private AuthenticationHandler defaultHandler;
-
-    /** The URI for the default AuthenticationHandler. */
-    private String defaultHandlerURI;
-
-    /**
-     * Gets the session manager to be used.
-     * 
-     * @return session manager to be used
-     */
-    public SessionManager getSessionManager() {
-        return sessionMgr;
-    }
-
-    /**
-     * Sets the session manager to be used.
-     * 
-     * @param manager session manager to be used.
-     */
-    public void setSessionManager(final SessionManager manager) {
-        sessionMgr = manager;
-    }
-
-    /**
-     * Get the map of {@link AuthenticationHandlers}.
-     * 
-     * @return The map of AuthenticationHandlers
-     */
-    public Map<String, AuthenticationHandler> getHandlerMap() {
-
-        return new FastMap<String, AuthenticationHandler>(handlerMap);
-    }
-
-    /**
-     * Set the {@link AuthenticationHandler} map.
-     * 
-     * @param handlerMap The Map of URIs to AuthenticationHandlers
-     */
-    public void setHandlerMap(final Map<String, AuthenticationHandler> handlerMap) {
-
-        for (String uri : handlerMap.keySet()) {
-            addHandlerMapping(uri, handlerMap.get(uri));
-        }
-    }
-
-    /**
-     * Add a <code>&lt;String:AuthenticationHandler&gr;</code> mapping to the AuthenticationManager's table. If a
-     * mapping for the URI already exists, it will be overwritten.
-     * 
-     * The URI SHOULD be from the saml-autn-context-2.0-os
-     * 
-     * @param uri A URI identifying the authentcation method.
-     * @param handler The AuthenticationHandler.
-     */
-    public void addHandlerMapping(String uri, AuthenticationHandler handler) {
-
-        if (uri == null || handler == null) {
-            return;
-        }
-
-        log.debug("AuthenticationManager: Registering " + handler.getClass().getName() + " for " + uri);
-
-        handlerMap.put(uri, handler);
-    }
-
-    /**
-     * Register the default {@link AuthenticationHandler}.
-     * 
-     * @param uri The URI of the default authentication handler (from saml-authn-context-2.0-os)
-     * @param handler The default {@link AuthenticationHandler}.
-     */
-    public void setDefaultHandler(String uri, AuthenticationHandler handler) {
-
-        log.debug("AuthenticationManager: Registering default handler " + handler.getClass().getName());
-
-        defaultHandler = handler;
-        defaultHandlerURI = uri;
-    }
-
-    /**
-     * Remove a <String:AuthenticationHandler> mapping from the AuthenticationManager's table.
-     * 
-     * The URI SHOULD be from the saml-authn-context-2.0-os
-     * 
-     * @param uri A URI identifying the authentcation method.
-     */
-    public void removeHandlerMapping(String uri) {
-
-        if (uri == null) {
-            return;
-        }
-
-        log.debug("AuthenticationManager: Unregistering handler for " + uri);
-
-        handlerMap.remove(uri);
-    }
-
-    /**
-     * Primary entrypoint for the AuthnManager.
-     * 
-     * @param req The ServletRequest.
-     * @param resp The ServletResponse.
-     */
-    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
-        if (req == null || resp == null) {
-            log.error("AuthenticationManager: Invalid parameters in AuthenticationManager's doPost().");
-            return;
-        }
-
-        HttpSession httpSession = req.getSession();
-        Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-
-        if (o == null || !(o instanceof LoginContext)) {
-            log.error("AuthenticationManager: Invalid login context object found in HttpSession.");
-            return;
-        }
-        LoginContext loginContext = (LoginContext) o;
-
-        // If authentication has been attempted, don't try it again.
-        if (loginContext.getAuthenticationAttempted()) {
-            handleNewAuthnRequest(loginContext, req, resp);
-        } else {
-            finishAuthnRequest(loginContext, req, resp);
-        }
-    }
-
-    /**
-     * Handle a new authentication request.
-     * 
-     * @param loginContext The {@link LoginContext} for the new authentication request
-     * @param servletRequest The servlet request containing the authn request
-     * @param servletResponse The associated servlet response.
-     */
-    private void handleNewAuthnRequest(final LoginContext loginContext, final HttpServletRequest servletRequest,
-            final HttpServletResponse servletResponse) throws ServletException, IOException {
-
-        boolean forceAuthN = loginContext.getForceAuth();
-        boolean passiveAuthN = loginContext.getPassiveAuth();
-
-        // set that authentication has been attempted, to prevent processing
-        // loops
-        loginContext.setAuthenticationAttempted();
-
-        // if the profile handler set a list of requested authn methods,
-        // evaluate them. otherwise, evaluate the default handler.
-        List<String> requestedAuthnMethods = loginContext.getRequestedAuthenticationMethods();
-        AuthenticationHandler handler = null;
-
-        if (requestedAuthnMethods == null) {
-
-            // if no authn methods were specified, try the default handler
-
-            if (evaluateHandler(defaultHandler, "default", forceAuthN, passiveAuthN)) {
-                handler = defaultHandler;
-                loginContext.setAuthenticationMethod(defaultHandlerURI);
-            }
-
-        } else {
-
-            // evaluate all requested authn methods until we find a match.
-
-            for (String authnMethodURI : requestedAuthnMethods) {
-
-                AuthenticationHandler candidateHandler = handlerMap.get(authnMethodURI);
-                if (candidateHandler == null) {
-                    log.debug("AuthenticationManager:  No registered authentication handlers can satisfy the "
-                            + " requested authentication method " + authnMethodURI);
-                    continue;
-                }
-
-                if (evaluateHandler(candidateHandler, authnMethodURI, forceAuthN, passiveAuthN)) {
-
-                    // we found a match. stop iterating.
-                    handler = candidateHandler;
-                    log.info("AuthenticationManager: Using authentication handler " + handler.getClass().getName()
-                            + " for authentication method " + authnMethodURI);
-                    loginContext.setAuthenticationMethod(authnMethodURI);
-                    break;
-                }
-            }
-        }
-
-        // if no acceptable handler was found, abort.
-        if (handler == null) {
-            loginContext.setAuthenticationOK(false);
-            loginContext
-                    .setAuthenticationFailureMessage("No installed AuthenticationHandler can satisfy the authentication request.");
-
-            log.error("AuthenticationManager:  No registered authentication handlers could satisify any requested "
-                    + "authentication methods. Unable to process authentication request.");
-
-            RequestDispatcher dispatcher = servletRequest.getRequestDispatcher(loginContext.getProfileHandlerURL());
-            dispatcher.forward(servletRequest, servletResponse);
-        }
-
-        // otherwise, forward control to the AuthenticationHandler
-        loginContext.setAuthenticationManagerURL(servletRequest.getRequestURI());
-        handler.login(servletRequest, servletResponse, loginContext);
-    }
-
-    /**
-     * Handle the "return leg" of an authentication request (i.e. clean up after an authentication handler has run).
-     * 
-     */
-    private void finishAuthnRequest(final LoginContext loginContext, final HttpServletRequest servletRequest,
-            final HttpServletResponse servletResponse) throws ServletException, IOException {
-
-        // if authentication was successful, the authentication handler should
-        // have updated the LoginContext with additional information. Use that
-        // info to create a Session.
-        if (loginContext.getAuthenticationOK()) {
-
-            AuthenticationMethodInformation authMethodInfo = new AuthenticationMethodInformationImpl(loginContext
-                    .getAuthenticationMethod(), loginContext.getAuthenticationInstant(), loginContext
-                    .getAuthenticationDuration());
-
-            InetAddress addr;
-            try {
-                addr = InetAddress.getByName(servletRequest.getRemoteAddr());
-            } catch (Exception ex) {
-                addr = null;
-            }
-
-            Session shibSession = (Session) sessionMgr.createSession(addr, loginContext.getUserID());
-            List<AuthenticationMethodInformation> authMethods = shibSession.getAuthenticationMethods();
-            authMethods.add(authMethodInfo);
-            loginContext.setSessionID(shibSession.getSessionID());
-        }
-
-        RequestDispatcher dispatcher = servletRequest.getRequestDispatcher(loginContext.getProfileHandlerURL());
-        dispatcher.forward(servletRequest, servletResponse);
-    }
-
-    /**
-     * "Stub" method for handling LogoutRequest.
-     */
-    private void handleLogoutRequest(final HttpServletRequest servletRequest, final HttpServletResponse servletResponse)
-            throws ServletException, IOException {
-
-    }
-
-    /**
-     * Evaluate an authenticationhandler against a set of evaluation criteria.
-     * 
-     * @param handler A candiate {@link AuthenticationHandler}
-     * @param description A description of the handler
-     * @param forceAuthN Is (re)authentication forced?
-     * @param passiveAuthN Can the AuthenticationHandler take control of the UI
-     * 
-     * @return <code>true</code> if handler meets the criteria, otherwise <code>false</code>
-     */
-    private boolean evaluateHandler(final AuthenticationHandler handler, String description, boolean forceAuthN,
-            boolean passiveAuthN) {
-
-        if (handler == null) {
-            return false;
-        }
-
-        if (forceAuthN && !handler.supportsForceAuthentication()) {
-            log.debug("AuthenticationManager: The RequestedAuthnContext required forced authentication, " + "but the "
-                    + description + " handler does not support that feature.");
-            return false;
-        }
-
-        if (passiveAuthN && !handler.supportsPassive()) {
-            log.debug("AuthenticationManager:  The RequestedAuthnContext required passive authentication, "
-                    + "but the " + description + " handler does not support that feature.");
-            return false;
-        }
-
-        return true;
-    }
-}
index c3b9670..924e7e4 100644 (file)
@@ -38,8 +38,8 @@ import org.joda.time.DateTime;
  * LoginContexts should be created by a profile handler when authentication is needed. Once control has returned to the
  * profile handler, it should remove the LoginContext from the HttpSession.
  * 
- * The {@link AuthenticationManager} or an {@link AuthenticationHandler} should set the
- * {@link LoginContext#setAuthenticationAttempted()}, {@link LoginContext#setAuthnOK(boolean)},
+ * The {@link AuthenticationEngine} or an {@link AuthenticationHandler} should set the
+ * {@link LoginContext#setAuthenticationAttempted()}, {@link LoginContext#setPrincipalAuthenticated(boolean)},
  * {@link LoginContext#setAuthnFailure(String)}, {@link LoginContext#{setAuthenticationDuration(long)}
  * {@link LoginContext#setAuthenticationInstant(DateTime)} appropriately.
  * 
@@ -50,7 +50,7 @@ public class LoginContext implements Serializable {
     public static final String LOGIN_CONTEXT_KEY = "shib2.logincontext";
 
     /** Serial version UID. */
-    private static final long serialVersionUID = 4268661186941572372L;
+    private static final long serialVersionUID = -8764003758734956911L;
 
     /** Entity ID of the relying party. */
     private String relyingPartyId;
@@ -74,10 +74,10 @@ public class LoginContext implements Serializable {
     private boolean authnAttempted;
 
     /** The id of the authenticated user. */
-    private String userID;
+    private String principalName;
 
     /** Did authentication succceed? */
-    private boolean authenticationOK;
+    private boolean principalAuthenticated;
 
     /** Optional failure message. */
     private String authnFailureMessage;
@@ -192,8 +192,8 @@ public class LoginContext implements Serializable {
      * 
      * @param authnOK if authentication succeeded;
      */
-    public void setAuthenticationOK(boolean authnOK) {
-        this.authenticationOK = authnOK;
+    public void setPrincipalAuthenticated(boolean authnOK) {
+        this.principalAuthenticated = authnOK;
     }
 
     /**
@@ -201,8 +201,8 @@ public class LoginContext implements Serializable {
      * 
      * @return <code>true</code> is the user was successfully authenticated.
      */
-    public boolean getAuthenticationOK() {
-        return authenticationOK;
+    public boolean isPrincipalAuthenticated() {
+        return principalAuthenticated;
     }
 
     /**
@@ -246,8 +246,8 @@ public class LoginContext implements Serializable {
      * 
      * @param id The userid.
      */
-    public void setUserID(String id) {
-        userID = id;
+    public void setPrincipalName(String id) {
+        principalName = id;
     }
 
     /**
@@ -255,8 +255,8 @@ public class LoginContext implements Serializable {
      * 
      * @return the ID of the user, or <code>null</code> if authentication failed.
      */
-    public String getUserID() {
-        return userID;
+    public String getPrincipalName() {
+        return principalName;
     }
 
     /**
@@ -368,10 +368,10 @@ public class LoginContext implements Serializable {
     }
 
     /**
-     * Return the acceptable authentication handler URIs for authenticating this user. If no authentication methods are
-     * preferred the resultant list will be empty.
+     * Return the acceptable authentication handler URIs, in preference order, for authenticating this user. If no
+     * authentication methods are preferred the resultant list will be empty.
      * 
-     * @return an array of URIs
+     * @return an list of authentication method identifiers
      */
     public List<String> getRequestedAuthenticationMethods() {
         return new ArrayList<String>();
diff --git a/src/edu/internet2/middleware/shibboleth/idp/authn/impl/AbstractAuthenticationHandler.java b/src/edu/internet2/middleware/shibboleth/idp/authn/impl/AbstractAuthenticationHandler.java
new file mode 100644 (file)
index 0000000..c102c15
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.impl;
+
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+
+/**
+ * Base class for authentication handlers.
+ */
+public abstract class AbstractAuthenticationHandler implements AuthenticationHandler {
+
+    /** Class logger. */
+    private final Logger log = Logger.getLogger(AbstractAuthenticationHandler.class);
+
+    /** Length of time, in milliseconds, after which a user should be re-authenticated. */
+    private long authenticationDuration;
+
+    /** Whether this handler supports foreced re-authentication. */
+    private boolean supportsForceAuthentication;
+
+    /** Whether this handler supports passive authentication. */
+    private boolean supportsPassive;
+
+    /** {@inheritDoc} */
+    public long getAuthenticationDuration() {
+        return authenticationDuration;
+    }
+
+    /**
+     * Sets the length of time, in milliseconds, after which a user should be re-authenticated.
+     * 
+     * @param duration length of time, in milliseconds, after which a user should be re-authenticated
+     */
+    public void setAuthenticationDurection(long duration) {
+        authenticationDuration = duration;
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsForceAuthentication() {
+        return supportsForceAuthentication;
+    }
+
+    /**
+     * Sets whether this handler supports foreced re-authentication.
+     * 
+     * @param supported whether this handler supports foreced re-authentication
+     */
+    public void setSupportsForceAuthentication(boolean supported) {
+        supportsForceAuthentication = supported;
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsPassive() {
+        return supportsPassive;
+    }
+
+    /**
+     * Sets whether this handler supports passive authentication.
+     * 
+     * @param supported whether this handler supports passive authentication.
+     */
+    public void setSupportsPassive(boolean supported) {
+        supportsPassive = supported;
+    }
+
+    /** {@inheritDoc} */
+    public void logout(HttpServletRequest request, HttpServletResponse response, String principal) {
+        // logout not yet supported
+    }
+}
\ No newline at end of file
index 412efcf..5605af0 100644 (file)
 package edu.internet2.middleware.shibboleth.idp.authn.impl;
 
 import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.List;
 import java.util.BitSet;
+import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.ServletRequest;
-
-import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import javax.servlet.ServletException;
 
 import org.apache.log4j.Logger;
-
 import org.joda.time.DateTime;
 
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
+
 /**
  * IP Address authentication handler.
  * 
- * This "authenticates" a user based on their IP address. It operates in either
- * default deny or default allow mode, and evaluates a given request against a
- * list of blocked or permitted IPs. It supports both IPv4 and IPv6.
+ * This "authenticates" a user based on their IP address. It operates in either default deny or default allow mode, and
+ * evaluates a given request against a list of blocked or permitted IPs. It supports both IPv4 and IPv6.
  * 
- * If an Authentication Context Class or DeclRef URI is not specified, it will
- * default to "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol".
+ * If an Authentication Context Class or DeclRef URI is not specified, it will default to
+ * "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol".
  */
-public class IPAddressHandler implements AuthenticationHandler {
-
-       /**
-        * Encapsulates a network address and a netmask on ipList.
-        */
-       protected class IPEntry {
-
-               /** The network address. */
-               private final BitSet networkAddress;
-
-               /** The netmask. */
-               private final BitSet netmask;
-
-               /**
-                * Construct a new IPEntry given a network address in CIDR format.
-                * 
-                * @param entry
-                *            A CIDR-formatted network address/netmask
-                * 
-                * @throws UnknownHostException
-                *             If entry is malformed.
-                */
-               public IPEntry(String entry) throws UnknownHostException {
-
-                       // quick sanity checks
-                       if (entry == null || entry.length() == 0) {
-                               throw new UnknownHostException("entry is null.");
-                       }
-
-                       int cidrOffset = entry.indexOf("/");
-                       if (cidrOffset == -1) {
-                               log.error("IPAddressHandler: invalid entry \"" + entry
-                                               + "\" -- it lacks a netmask component.");
-                               throw new UnknownHostException(
-                                               "entry lacks a netmask component.");
-                       }
-
-                       // ensure that only one "/" is present.
-                       if (entry.indexOf("/", cidrOffset + 1) != -1) {
-                               log.error("IPAddressHandler: invalid entry \"" + entry
-                                               + "\" -- too many \"/\" present.");
-                               throw new UnknownHostException(
-                                               "entry has too many netmask components.");
-                       }
-
-                       String networkString = entry.substring(0, cidrOffset);
-                       String netmaskString = entry.substring(cidrOffset + 1, entry
-                                       .length());
-
-                       InetAddress tempAddr = InetAddress.getByName(networkString);
-                       networkAddress = byteArrayToBitSet(tempAddr.getAddress());
-
-                       int masklen = Integer.parseInt(netmaskString);
-                       int addrlen = networkAddress.length();
-
-                       // ensure that the netmask isn't too large
-                       if ((tempAddr instanceof Inet4Address) && (masklen > 32)) {
-                               throw new UnknownHostException(
-                                               "IPAddressHandler: Netmask is too large for an IPv4 address: "
-                                                               + masklen);
-                       } else if ((tempAddr instanceof Inet6Address) && masklen > 128) {
-                               throw new UnknownHostException(
-                                               "IPAddressHandler: Netmask is too large for an IPv6 address: "
-                                                               + masklen);
-                       }
-
-                       netmask = new BitSet(addrlen);
-                       netmask.set(addrlen - masklen, addrlen, true);
-               }
-
-               /**
-                * Get the network address.
-                * 
-                * @return the network address.
-                */
-               public BitSet getNetworkAddress() {
-                       return networkAddress;
-               }
-
-               /**
-                * Get the netmask.
-                * 
-                * @return the netmask.
-                */
-               public BitSet getNetmask() {
-                       return netmask;
-               }
-       }
-
-       private static final Logger log = Logger.getLogger(IPAddressHandler.class);
-
-       /** The URI of the AuthnContextDeclRef or the AuthnContextClass */
-       private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol";
-
-       /** The username to use for IP-address "authenticated" users. */
-       private String username;
-
-       /** Are the IPs in ipList a permitted list or a deny list */
-       private boolean defaultDeny;
-
-       /** The list of denied or permitted IPs */
-       private List<IPEntry> ipList;
-
-       /** Creates a new instance of IPAddressHandler */
-       public IPAddressHandler() {
-       }
-
-       /**
-        * Set the permitted IP addresses.
-        * 
-        * If <code>defaultDeny</code> is <code>true</code> then only the IP
-        * addresses in <code>ipList</code> will be "authenticated." If
-        * <code>defaultDeny</code> is <code>false</code>, then all IP
-        * addresses except those in <code>ipList</code> will be authenticated.
-        * 
-        * @param entries
-        *            A list of IP addresses (with CIDR masks).
-        * @param defaultDeny
-        *            Does <code>ipList</code> contain a deny or permit list.
-        */
-       public void setEntries(final List<String> entries, boolean defaultDeny) {
-
-               this.defaultDeny = defaultDeny;
-               ipList = new CopyOnWriteArrayList<IPEntry>();
-
-               for (String addr : entries) {
-                       try {
-                               ipList
-                                               .add(new edu.internet2.middleware.shibboleth.idp.authn.impl.IPAddressHandler.IPEntry(
-                                                               addr));
-                       } catch (UnknownHostException ex) {
-                               log.error("IPAddressHandler: Error parsing entry \"" + addr
-                                               + "\". Ignoring.");
-                       }
-               }
-       }
-
-       /** @{inheritDoc} */
-       public boolean supportsPassive() {
-               return true;
-       }
-
-       /** {@inheritDoc} */
-       public boolean supportsForceAuthentication() {
-               return true;
-       }
-
-       /**
-        * Set the username to use for all IP-address authenticated users.
-        * 
-        * @param username
-        *            The username for IP-address authenticated users.
-        */
-       public void setUsername(String username) {
-               this.username = username;
-       }
-
-       /**
-        * Get the username for all IP-address authenticated users.
-        * 
-        * @return The username for IP-address authenticated users.
-        */
-       public String getUsername() {
-               return username;
-       }
-
-       /** {@inheritDoc} */
-       public void logout(final HttpServletRequest request,
-                       final HttpServletResponse response, final String principal) {
-
-               // RequestDispatcher dispatcher = request
-               // .getRequestDispatcher(returnLocation);
-               // dispatcher.forward(request, response);
-       }
-
-       /** {@inheritDoc} */
-       public void login(final HttpServletRequest request,
-                       final HttpServletResponse response, final LoginContext loginCtx) {
-
-               loginCtx.setAuthenticationAttempted();
-               loginCtx.setAuthenticationInstant(new DateTime());
-               loginCtx.setUserID(username);
-
-               if (defaultDeny) {
-                       handleDefaultDeny(request, response, loginCtx);
-               } else {
-                       handleDefaultAllow(request, response, loginCtx);
-               }
-
-               // return control back to the AuthNManager.
-               try {
-                       RequestDispatcher dispatcher = request
-                                       .getRequestDispatcher(loginCtx
-                                                       .getAuthenticationManagerURL());
-                       dispatcher.forward(request, response);
-               } catch (ServletException ex) {
-                       log
-                                       .error(
-                                                       "IPAddressHandler: Error returning control to AuthnManager.",
-                                                       ex);
-               } catch (IOException ex) {
-                       log
-                                       .error(
-                                                       "IPAddressHandler: Error returning control to AuthnManager.",
-                                                       ex);
-               }
-       }
-
-       protected void handleDefaultDeny(HttpServletRequest request,
-                       HttpServletResponse response, LoginContext loginCtx) {
-
-               boolean ipAllowed = searchIpList(request);
-
-               if (ipAllowed) {
-                       loginCtx.setAuthenticationOK(true);
-               } else {
-                       loginCtx.setAuthenticationOK(false);
-                       loginCtx
-                                       .setAuthenticationFailureMessage("The user's IP address is not in the permitted list.");
-               }
-       }
-
-       protected void handleDefaultAllow(HttpServletRequest request,
-                       HttpServletResponse response, LoginContext loginCtx) {
-
-               boolean ipDenied = searchIpList(request);
-
-               if (ipDenied) {
-                       loginCtx.setAuthenticationOK(false);
-                       loginCtx
-                                       .setAuthenticationFailureMessage("The sser's IP address is in the deny list.");
-               } else {
-                       loginCtx.setAuthenticationOK(true);
-               }
-       }
-
-       /**
-        * Search the list of InetAddresses for the client's address.
-        * 
-        * @param request
-        *            The ServletReqeust
-        * 
-        * @return <code>true</code> if the client's address is in
-        *         <code>ipList</code>
-        */
-       private boolean searchIpList(final ServletRequest request) {
-
-               boolean found = false;
-
-               try {
-                       InetAddress addr = InetAddress.getByName(request.getRemoteAddr());
-                       BitSet addrbits = byteArrayToBitSet(addr.getAddress());
-
-                       for (IPEntry entry : ipList) {
-
-                               BitSet netaddr = entry.getNetworkAddress();
-                               BitSet netmask = entry.getNetmask();
-
-                               addrbits.and(netmask);
-                               if (addrbits.equals(netaddr)) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-
-               } catch (UnknownHostException ex) {
-                       log.error("IPAddressHandler: Error resolving hostname.", ex);
-                       return false;
-               }
-
-               return found;
-       }
-
-       /**
-        * Converts a byte array to a BitSet.
-        * 
-        * The supplied byte array is assumed to have the most signifigant bit in
-        * element 0.
-        * 
-        * @param bytes
-        *            the byte array with most signifigant bit in element 0.
-        * 
-        * @return the BitSet
-        */
-       protected static BitSet byteArrayToBitSet(final byte[] bytes) {
-
-               BitSet bits = new BitSet();
-
-               for (int i = 0; i < bytes.length * 8; i++) {
-                       if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
-                               bits.set(i);
-                       }
-               }
-
-               return bits;
-       }
-}
+public class IPAddressHandler extends AbstractAuthenticationHandler {
+
+    /** Class logger. */
+    private final Logger log = Logger.getLogger(IPAddressHandler.class);
+
+    /** The URI of the AuthnContextDeclRef or the AuthnContextClass. */
+    private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol";
+
+    /** The username to use for IP-address "authenticated" users. */
+    private String username;
+
+    /** Are the IPs in ipList a permitted list or a deny list. */
+    private boolean defaultDeny;
+
+    /** The list of denied or permitted IPs. */
+    private List<IPEntry> ipList;
+
+    /**
+     * Set the permitted IP addresses.
+     * 
+     * If <code>defaultDeny</code> is <code>true</code> then only the IP addresses in <code>ipList</code> will be
+     * "authenticated." If <code>defaultDeny</code> is <code>false</code>, then all IP addresses except those in
+     * <code>ipList</code> will be authenticated.
+     * 
+     * @param entries A list of IP addresses (with CIDR masks).
+     * @param defaultDeny Does <code>ipList</code> contain a deny or permit list.
+     */
+    public void setEntries(final List<String> entries, boolean defaultDeny) {
+
+        this.defaultDeny = defaultDeny;
+        ipList = new CopyOnWriteArrayList<IPEntry>();
+
+        for (String addr : entries) {
+            try {
+                ipList.add(new edu.internet2.middleware.shibboleth.idp.authn.impl.IPAddressHandler.IPEntry(addr));
+            } catch (UnknownHostException ex) {
+                log.error("IPAddressHandler: Error parsing entry \"" + addr + "\". Ignoring.");
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsPassive() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public boolean supportsForceAuthentication() {
+        return true;
+    }
+
+    /**
+     * Get the username for all IP-address authenticated users.
+     * 
+     * @return The username for IP-address authenticated users.
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Set the username to use for all IP-address authenticated users.
+     * 
+     * @param name The username for IP-address authenticated users.
+     */
+    public void setUsername(String name) {
+        username = name;
+    }
+
+    /** {@inheritDoc} */
+    public void login(LoginContext loginContext, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+
+        loginContext.setAuthenticationAttempted();
+        loginContext.setAuthenticationInstant(new DateTime());
+        loginContext.setPrincipalName(username);
+
+        if (defaultDeny) {
+            handleDefaultDeny(httpRequest, httpResponse, loginContext);
+        } else {
+            handleDefaultAllow(httpRequest, httpResponse, loginContext);
+        }
+
+        // return control back to the AuthNManager.
+        try {
+            RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginContext.getAuthenticationManagerURL());
+            dispatcher.forward(httpRequest, httpResponse);
+        } catch (ServletException ex) {
+            log.error("IPAddressHandler: Error returning control to AuthnManager.", ex);
+        } catch (IOException ex) {
+            log.error("IPAddressHandler: Error returning control to AuthnManager.", ex);
+        }
+    }
+
+    protected void handleDefaultDeny(HttpServletRequest request, HttpServletResponse response, LoginContext loginCtx) {
+
+        boolean ipAllowed = searchIpList(request);
+
+        if (ipAllowed) {
+            loginCtx.setPrincipalAuthenticated(true);
+        } else {
+            loginCtx.setPrincipalAuthenticated(false);
+            loginCtx.setAuthenticationFailureMessage("The user's IP address is not in the permitted list.");
+        }
+    }
+
+    protected void handleDefaultAllow(HttpServletRequest request, HttpServletResponse response, LoginContext loginCtx) {
+
+        boolean ipDenied = searchIpList(request);
+
+        if (ipDenied) {
+            loginCtx.setPrincipalAuthenticated(false);
+            loginCtx.setAuthenticationFailureMessage("The user's IP address is in the deny list.");
+        } else {
+            loginCtx.setPrincipalAuthenticated(true);
+        }
+    }
+
+    /**
+     * Search the list of InetAddresses for the client's address.
+     * 
+     * @param request The ServletReqeust
+     * 
+     * @return <code>true</code> if the client's address is in <code>ipList</code>
+     */
+    private boolean searchIpList(ServletRequest request) {
+
+        boolean found = false;
+
+        try {
+            InetAddress addr = InetAddress.getByName(request.getRemoteAddr());
+            BitSet addrbits = byteArrayToBitSet(addr.getAddress());
+
+            for (IPEntry entry : ipList) {
+
+                BitSet netaddr = entry.getNetworkAddress();
+                BitSet netmask = entry.getNetmask();
+
+                addrbits.and(netmask);
+                if (addrbits.equals(netaddr)) {
+                    found = true;
+                    break;
+                }
+            }
+
+        } catch (UnknownHostException ex) {
+            log.error("IPAddressHandler: Error resolving hostname.", ex);
+            return false;
+        }
+
+        return found;
+    }
+
+    /**
+     * Converts a byte array to a BitSet.
+     * 
+     * The supplied byte array is assumed to have the most signifigant bit in element 0.
+     * 
+     * @param bytes the byte array with most signifigant bit in element 0.
+     * 
+     * @return the BitSet
+     */
+    protected BitSet byteArrayToBitSet(final byte[] bytes) {
+
+        BitSet bits = new BitSet();
+
+        for (int i = 0; i < bytes.length * 8; i++) {
+            if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
+                bits.set(i);
+            }
+        }
+
+        return bits;
+    }
+
+    /**
+     * Encapsulates a network address and a netmask on ipList.
+     */
+    protected class IPEntry {
+
+        /** The network address. */
+        private final BitSet networkAddress;
+
+        /** The netmask. */
+        private final BitSet netmask;
+
+        /**
+         * Construct a new IPEntry given a network address in CIDR format.
+         * 
+         * @param entry A CIDR-formatted network address/netmask
+         * 
+         * @throws UnknownHostException If entry is malformed.
+         */
+        public IPEntry(String entry) throws UnknownHostException {
+
+            // quick sanity checks
+            if (entry == null || entry.length() == 0) {
+                throw new UnknownHostException("entry is null.");
+            }
+
+            int cidrOffset = entry.indexOf("/");
+            if (cidrOffset == -1) {
+                log.error("IPAddressHandler: invalid entry \"" + entry + "\" -- it lacks a netmask component.");
+                throw new UnknownHostException("entry lacks a netmask component.");
+            }
+
+            // ensure that only one "/" is present.
+            if (entry.indexOf("/", cidrOffset + 1) != -1) {
+                log.error("IPAddressHandler: invalid entry \"" + entry + "\" -- too many \"/\" present.");
+                throw new UnknownHostException("entry has too many netmask components.");
+            }
+
+            String networkString = entry.substring(0, cidrOffset);
+            String netmaskString = entry.substring(cidrOffset + 1, entry.length());
+
+            InetAddress tempAddr = InetAddress.getByName(networkString);
+            networkAddress = byteArrayToBitSet(tempAddr.getAddress());
+
+            int masklen = Integer.parseInt(netmaskString);
+            int addrlen = networkAddress.length();
+
+            // ensure that the netmask isn't too large
+            if ((tempAddr instanceof Inet4Address) && (masklen > 32)) {
+                throw new UnknownHostException("IPAddressHandler: Netmask is too large for an IPv4 address: " 
+                        + masklen);
+            } else if ((tempAddr instanceof Inet6Address) && masklen > 128) {
+                throw new UnknownHostException("IPAddressHandler: Netmask is too large for an IPv6 address: " 
+                        + masklen);
+            }
+
+            netmask = new BitSet(addrlen);
+            netmask.set(addrlen - masklen, addrlen, true);
+        }
+
+        /**
+         * Get the network address.
+         * 
+         * @return the network address.
+         */
+        public BitSet getNetworkAddress() {
+            return networkAddress;
+        }
+
+        /**
+         * Get the netmask.
+         * 
+         * @return the netmask.
+         */
+        public BitSet getNetmask() {
+            return netmask;
+        }
+    }
+}
\ No newline at end of file
index a2f4b88..1d66108 100644 (file)
@@ -18,65 +18,24 @@ package edu.internet2.middleware.shibboleth.idp.authn.impl;
 
 import java.io.IOException;
 
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
+import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
 
 /**
- * This servlet should be protected by a filter which populates REMOTE_USER. The
- * serlvet will then set the remote user field in a LoginContext.
+ * Extracts the REMOTE_USER and places it in a request attribute to be used by the authentication engine.
  */
 public class RemoteUserAuthServlet extends HttpServlet {
 
-       private static final Logger log = Logger
-                       .getLogger(RemoteUserAuthServlet.class);
-
-       public RemoteUserAuthServlet() {
-       }
-
-       public void doPost(HttpServletRequest request, HttpServletResponse response)
-                       throws IOException {
-
-               HttpSession httpSession = request.getSession();
-
-               Object o = httpSession.getAttribute(LoginContext.LOGIN_CONTEXT_KEY);
-               if (!(o instanceof LoginContext)) {
-                       log
-                                       .error("RemoteUSerAuthServlet - Invalid login context object -- object is not an instance of LoginContext");
-                       return; // where this will return to, I don't know.
-               }
-
-               LoginContext loginContext = (LoginContext) o;
-
-               loginContext.setAuthenticationInstant(new DateTime());
-
-               String remoteUser = request.getRemoteUser();
-               if (remoteUser == null || remoteUser.length() == 0) {
-                       loginContext.setAuthenticationOK(false);
-               } else {
-                       loginContext.setAuthenticationOK(true);
-                       loginContext.setUserID(remoteUser);
-               }
+    /** Serial version UID. */
+    private static final long serialVersionUID = 1968754704168240644L;
 
-               // redirect the user back to the AuthenticationManager
-               try {
-                       RequestDispatcher dispatcher = request
-                                       .getRequestDispatcher(loginContext
-                                                       .getAuthenticationManagerURL());
-                       dispatcher.forward(request, response);
-               } catch (ServletException ex) {
-                       log
-                                       .error(
-                                                       "RemoteUserAuthServlet: Error redirecting back to AuthenticationManager",
-                                                       ex);
-               }
-       }
-}
+    /** {@inheritDoc} */
+    public void doPost(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException {
+        httpRequest.setAttribute(AuthenticationHandler.PRINCIPAL_NAME_KEY, httpRequest.getRemoteUser());
+        AuthenticationEngine.returnToAuthenticationEngine(httpRequest, httpResponse);
+    }
+}
\ No newline at end of file
index bb0e729..4ee98d8 100644 (file)
@@ -19,130 +19,54 @@ package edu.internet2.middleware.shibboleth.idp.authn.impl;
 import java.io.IOException;
 
 import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationHandler;
-import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
-
 import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
+
+import edu.internet2.middleware.shibboleth.idp.authn.LoginContext;
 
 /**
- * {@link AuthenticationHandler} that redirects to servlet protected by a Web
- * Single-Sign-On system.
+ * Authentication Handler that redirects to servlet protected by a Web Single-Sign-On system.
  */
-public class RemoteUserAuthenticationHandler implements AuthenticationHandler {
-
-       private static final Logger log = Logger
-                       .getLogger(RemoteUserAuthenticationHandler.class);
-
-       /** The URI of the AuthnContextDeclRef or the AuthnContextClass. */
-       private String authnMethodURI;
-
-       /** The duration of the authNContext. */
-       private long authnDuration;
-
-       /** The URL of the SSO-protected servlet. */
-       private String servletURL;
-
-       private boolean supportsPassive = false;
-
-       private boolean supportsForce = false;
-
-       /** Creates a new instance of RemoteUserAuthenticationHandler */
-       public RemoteUserAuthenticationHandler() {
-       }
-
-       public void setSupportsPassive(boolean supportsPassive) {
-               this.supportsPassive = supportsPassive;
-       }
-
-       public void setSupportsForce(boolean supportsForce) {
-               this.supportsForce = supportsForce;
-       }
-
-       public boolean supportsPassive() {
-               return supportsPassive;
-       }
-
-       public boolean supportsForceAuthentication() {
-               return supportsForce;
-       }
-
-       /**
-        * Set the duration of the AuthnContext.
-        * 
-        * @param duration
-        *            The duration of the AuthnContext.
-        */
-       public void setAuthnDuration(long duration) {
-               authnDuration = duration;
-       }
-
-       /**
-        * Return the duration of the AuthnContext.
-        * 
-        * @return the duration of the AuthnContext.
-        */
-       public long getAuthnDuration() {
-               return authnDuration;
-       }
-
-       /**
-        * Set the SSO-protected servlet's URL.
-        * 
-        * @param servletURL
-        *            The URL of the SSO-protected servlet.
-        */
-       public void setServletURL(String servletURL) {
-               this.servletURL = servletURL;
-       }
-
-       /**
-        * Get the URL of the SSO-protected servlet.
-        * 
-        * @return The URL of the SSO-protected servlet.
-        */
-       public String getServletURL() {
-               return servletURL;
-       }
-
-       /** @{inheritDoc} */
-       public void login(final HttpServletRequest request,
-                       final HttpServletResponse response, final LoginContext loginCtx) {
-
-               // set some initial values.
-               loginCtx.setAuthenticationAttempted();
-               loginCtx.setAuthenticationMethod(authnMethodURI);
-               loginCtx.setAuthenticationDuration(authnDuration);
-
-               // forward control to the servlet.
-               try {
-                       RequestDispatcher dispatcher = request
-                                       .getRequestDispatcher(servletURL);
-                       dispatcher.forward(request, response);
-               } catch (IOException ex) {
-                       log
-                                       .error(
-                                                       "RemoteUserAuthenticationHandler: Unable to forward control to SSO servlet.",
-                                                       ex);
-               } catch (ServletException ex) {
-                       log
-                                       .error(
-                                                       "RemoteUserAuthenticationHandler: Unable to forward control to SSO servlet.",
-                                                       ex);
-               }
-
-       }
-
-       /** @{inheritDoc} */
-       public void logout(final HttpServletRequest request,
-                       final HttpServletResponse response, String principal) {
-
-       }
-
-}
+public class RemoteUserAuthenticationHandler extends AbstractAuthenticationHandler {
+
+    /** Class logger. */
+    private final Logger log = Logger.getLogger(RemoteUserAuthenticationHandler.class);
+
+    /** The URL of the SSO-protected servlet. */
+    private String servletURL;
+
+    /**
+     * Set the SSO-protected servlet's URL.
+     * 
+     * @param url The URL of the SSO-protected servlet.
+     */
+    public void setServletURL(String url) {
+        servletURL = url;
+    }
+
+    /**
+     * Get the URL of the SSO-protected servlet.
+     * 
+     * @return The URL of the SSO-protected servlet.
+     */
+    public String getServletURL() {
+        return servletURL;
+    }
+
+    /** {@inheritDoc} */
+    public void login(LoginContext loginContext, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
+
+        // forward control to the servlet.
+        try {
+            RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(servletURL);
+            dispatcher.forward(httpRequest, httpResponse);
+        } catch (IOException ex) {
+            log.error("RemoteUserAuthenticationHandler: Unable to forward control to SSO servlet.", ex);
+        } catch (ServletException ex) {
+            log.error("RemoteUserAuthenticationHandler: Unable to forward control to SSO servlet.", ex);
+        }
+    }
+}
\ No newline at end of file
index 08fc167..4f362d8 100644 (file)
@@ -32,200 +32,180 @@ import org.joda.time.DateTime;
 /**
  * Authenticate a username and password against a JAAS source.
  * 
- * This {@link AuthenticationHandler} requires a JSP to collect a username and
- * password from the user. It also requires a JAAS configuration file to
- * validate the username and password.
+ * This {@link AuthenticationHandler} requires a JSP to collect a username and password from the user. It also requires
+ * a JAAS configuration file to validate the username and password.
  * 
- * If an Authentication Context Class or DeclRef URI is not specified, it will
- * default to
+ * If an Authentication Context Class or DeclRef URI is not specified, it will default to
  * "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport".
  */
-public class UsernamePasswordAuthenticationHandler implements
-               AuthenticationHandler {
+public class UsernamePasswordAuthenticationHandler extends AbstractAuthenticationHandler {
 
-       /** Key in an HttpSession for the JAAS configuration name. */
-       public static final String JAAS_CONFIG_NAME = "UsernamePasswordAuthenticationHandler.JAAS_CONFIG_NAME";
+    /** Key in an HttpSession for the JAAS configuration name. */
+    public static final String JAAS_CONFIG_NAME = "UsernamePasswordAuthenticationHandler.JAAS_CONFIG_NAME";
 
-       /** Key in an HttpSession for the username. */
-       public static final String USERNAME = "UsernamePasswordAuthenticationHandler.USERNAME";
-
-       /** Key in an HttpSession for the authentication instant. */
-       public static final String AUTHN_INSTANT = "UsernamePasswordAuthenticationHandler.AUTHN_INSTANT";
-
-       private static final Logger log = Logger
-                       .getLogger(UsernamePasswordAuthenticationHandler.class);
+    /** Key in an HttpSession for the username. */
+    public static final String USERNAME = "UsernamePasswordAuthenticationHandler.USERNAME";
 
-       /** The name of the JAAS Configuration to use. */
-       protected String jaasConfigurationName;
+    /** Key in an HttpSession for the authentication instant. */
+    public static final String AUTHN_INSTANT = "UsernamePasswordAuthenticationHandler.AUTHN_INSTANT";
 
-       /** The name of the login page. */
-       protected String loginURL;
-
-       /** The authN duration, in seconds. */
-       protected int authnDuration;
-
-       /** The URI of the AuthnContextDeclRef or the AuthnContextClass */
-       private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport";
-
-       public UsernamePasswordAuthenticationHandler() {
-       }
-
-       /** @{inheritDoc} */
-       public boolean supportsPassive() {
-               return true;
-       }
-
-       /** @{inheritDoc} */
-       public boolean supportsForceAuthentication() {
-               return true;
-       }
-
-       /** {@inheritDoc} */
-       public void login(
-                       final HttpServletRequest request,
-                       final HttpServletResponse response,
-                       final edu.internet2.middleware.shibboleth.idp.authn.LoginContext loginCtx) {
-
-               HttpSession session = request.getSession();
-
-               // these fields will need to be set, regardless of how we branch.
-               loginCtx.setAuthenticationAttempted();
-               loginCtx.setAuthenticationMethod(authnMethodURI);
-
-               // If forceAuth is set, we must forward to the login JSP.
-               if (loginCtx.getForceAuth()) {
-
-                       if (loginCtx.getPassiveAuth()) {
-                               log
-                                               .error("UsernamePasswordAuthenticationHandler: Unable to authenticate user: both forceAuthN and passiveAuthnN are set in the login context.");
-                               redirectControl(loginCtx.getAuthenticationManagerURL(),
-                                               "AuthenticationManager", request, response);
-                       }
-
-                       session.setAttribute(JAAS_CONFIG_NAME, jaasConfigurationName);
-                       redirectControl(loginURL, "login page", request, response);
-               }
-
-               // If the user has already been authenticated, forceAuth is not set,
-               // and the authentication hasn't expired, then populate the LoginCtx
-               // and return control to the AuthenticationManager.
-               // Otherwise, redirect the user to loginJSPURL to collect a username and
-               // password.
-
-               // implementation note: There is a race condition here, but I'm not sure
-               // how to avoid it. I need a way to instantiate a lock in the session to
-               // protect the
-               // username and authnInstant fields.
-
-               Object o = session.getAttribute(USERNAME);
-               if (!(o instanceof String)) {
-                       log
-                                       .debug("UsernamePasswordAuthenticationHandler: Username attribute found in HttpSession, but it is not a String.");
-
-                       redirectControl(loginURL, "login page", request, response);
-               }
-
-               String username = (String) o;
-
-               o = session.getAttribute(AUTHN_INSTANT);
-               if (!(o instanceof DateTime)) {
-                       log
-                                       .debug("UsernamePasswordAuthenticationHandler: AuthnInstant attribute found in HttpSession for user "
-                                                       + username + ", but it is not a DateTime.");
-
-                       redirectControl(loginURL, "login page", request, response);
-               }
-
-               DateTime authnInstant = (DateTime) o;
-               DateTime authnExpires = authnInstant.plusSeconds(authnDuration);
-               DateTime now = new DateTime();
-               if (now.isAfter(authnExpires)) {
-                       log
-                                       .info("UsernamePasswordAuthenticationHandler: Authentication has expired for user "
-                                                       + username);
-                       redirectControl(loginURL, "login page", request, response);
-               }
-
-               // the current authentication information is still valid, so return it.
-               loginCtx.setAuthenticationOK(true);
-               loginCtx.setUserID(username);
-               loginCtx.setAuthenticationInstant(authnInstant);
-
-               // XXX: adjust for the appropriate units?
-               loginCtx.setAuthenticationDuration(authnDuration);
-
-       }
-
-       /** {@inheritDoc} */
-       public void logout(final HttpServletRequest request,
-                       final HttpServletResponse response, String principal) {
-               return;
-       }
-
-       /**
-        * Set the name of the JAAS Configuration to use for user authentication.
-        * 
-        * @param configurationName
-        *            The name of the JAAS Configuration entry.
-        */
-       public void setJAASConfigurationName(String configurationName) {
-               jaasConfigurationName = configurationName;
-       }
-
-       /**
-        * Get the name of the JAAS Configuraiton to use for user authentication.
-        * 
-        * @return The name of the JAAS Configuration entry.
-        */
-       public String getJAASConfiguraitonName() {
-               return jaasConfigurationName;
-       }
-
-       /**
-        * Set the duration of the authentication.
-        * 
-        * @param duration
-        *            The duration, in seconds, of the authentication.
-        */
-       public void setAuthNDuration(int duration) {
-               authnDuration = duration;
-       }
-
-       /**
-        * Get the duration of the authentication.
-        * 
-        * @return The duration, in seconds, of the authentication.
-        */
-       public int getAuthNDuration() {
-               return authnDuration;
-       }
-
-       /**
-        * Return control to the AuthNManager.
-        * 
-        * @param url
-        *            The URL to which control should be redirected.
-        * @param urlDescription
-        *            An optional textual description of <code>url</code>.
-        * @param request
-        *            The HttpServletRequest.
-        * @param response
-        *            The HttpServletResponse.
-        */
-       protected void redirectControl(String url, String urlDescription,
-                       final HttpServletRequest request, final HttpServletResponse response) {
-
-               try {
-                       RequestDispatcher dispatcher = request.getRequestDispatcher(url);
-                       dispatcher.forward(request, response);
-               } catch (ServletException ex) {
-                       log.error(
-                                       "UsernamePasswordAuthenticationHandler: Error returning control to "
-                                                       + urlDescription, ex);
-               } catch (IOException ex) {
-                       log.error(
-                                       "UsernamePasswordAuthenticationHandler: Error returning control to "
-                                                       + urlDescription, ex);
-               }
-       }
+    private static final Logger log = Logger.getLogger(UsernamePasswordAuthenticationHandler.class);
+
+    /** The name of the JAAS Configuration to use. */
+    protected String jaasConfigurationName;
+
+    /** The name of the login page. */
+    protected String loginURL;
+
+    /** The authN duration, in seconds. */
+    protected int authnDuration;
+
+    /** The URI of the AuthnContextDeclRef or the AuthnContextClass */
+    private String authnMethodURI = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport";
+
+    public UsernamePasswordAuthenticationHandler() {
+    }
+
+    /** @{inheritDoc} */
+    public boolean supportsPassive() {
+        return true;
+    }
+
+    /** @{inheritDoc} */
+    public boolean supportsForceAuthentication() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public void login(final edu.internet2.middleware.shibboleth.idp.authn.LoginContext loginContext,
+            final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
+
+        HttpSession session = httpRequest.getSession();
+
+        // these fields will need to be set, regardless of how we branch.
+        loginContext.setAuthenticationAttempted();
+        loginContext.setAuthenticationMethod(authnMethodURI);
+
+        // If forceAuth is set, we must forward to the login JSP.
+        if (loginContext.getForceAuth()) {
+
+            if (loginContext.getPassiveAuth()) {
+                log
+                        .error("UsernamePasswordAuthenticationHandler: Unable to authenticate user: both forceAuthN and passiveAuthnN are set in the login context.");
+                redirectControl(loginContext.getAuthenticationManagerURL(), "AuthenticationManager", httpRequest,
+                        httpResponse);
+            }
+
+            session.setAttribute(JAAS_CONFIG_NAME, jaasConfigurationName);
+            redirectControl(loginURL, "login page", httpRequest, httpResponse);
+        }
+
+        // If the user has already been authenticated, forceAuth is not set,
+        // and the authentication hasn't expired, then populate the LoginCtx
+        // and return control to the AuthenticationManager.
+        // Otherwise, redirect the user to loginJSPURL to collect a username and
+        // password.
+
+        // implementation note: There is a race condition here, but I'm not sure
+        // how to avoid it. I need a way to instantiate a lock in the session to
+        // protect the
+        // username and authnInstant fields.
+
+        Object o = session.getAttribute(USERNAME);
+        if (!(o instanceof String)) {
+            log
+                    .debug("UsernamePasswordAuthenticationHandler: Username attribute found in HttpSession, but it is not a String.");
+
+            redirectControl(loginURL, "login page", httpRequest, httpResponse);
+        }
+
+        String username = (String) o;
+
+        o = session.getAttribute(AUTHN_INSTANT);
+        if (!(o instanceof DateTime)) {
+            log.debug("UsernamePasswordAuthenticationHandler: AuthnInstant attribute found in HttpSession for user "
+                    + username + ", but it is not a DateTime.");
+
+            redirectControl(loginURL, "login page", httpRequest, httpResponse);
+        }
+
+        DateTime authnInstant = (DateTime) o;
+        DateTime authnExpires = authnInstant.plusSeconds(authnDuration);
+        DateTime now = new DateTime();
+        if (now.isAfter(authnExpires)) {
+            log.info("UsernamePasswordAuthenticationHandler: Authentication has expired for user " + username);
+            redirectControl(loginURL, "login page", httpRequest, httpResponse);
+        }
+
+        // the current authentication information is still valid, so return it.
+        loginContext.setPrincipalAuthenticated(true);
+        loginContext.setPrincipalName(username);
+        loginContext.setAuthenticationInstant(authnInstant);
+
+        // XXX: adjust for the appropriate units?
+        loginContext.setAuthenticationDuration(authnDuration);
+
+    }
+
+    /** {@inheritDoc} */
+    public void logout(final HttpServletRequest request, final HttpServletResponse response, String principal) {
+        return;
+    }
+
+    /**
+     * Set the name of the JAAS Configuration to use for user authentication.
+     * 
+     * @param configurationName The name of the JAAS Configuration entry.
+     */
+    public void setJAASConfigurationName(String configurationName) {
+        jaasConfigurationName = configurationName;
+    }
+
+    /**
+     * Get the name of the JAAS Configuraiton to use for user authentication.
+     * 
+     * @return The name of the JAAS Configuration entry.
+     */
+    public String getJAASConfiguraitonName() {
+        return jaasConfigurationName;
+    }
+
+    /**
+     * Set the duration of the authentication.
+     * 
+     * @param duration The duration, in seconds, of the authentication.
+     */
+    public void setAuthNDuration(int duration) {
+        authnDuration = duration;
+    }
+
+    /**
+     * Get the duration of the authentication.
+     * 
+     * @return The duration, in seconds, of the authentication.
+     */
+    public int getAuthNDuration() {
+        return authnDuration;
+    }
+
+    /**
+     * Return control to the AuthNManager.
+     * 
+     * @param url The URL to which control should be redirected.
+     * @param urlDescription An optional textual description of <code>url</code>.
+     * @param request The HttpServletRequest.
+     * @param response The HttpServletResponse.
+     */
+    protected void redirectControl(String url, String urlDescription, final HttpServletRequest request,
+            final HttpServletResponse response) {
+
+        try {
+            RequestDispatcher dispatcher = request.getRequestDispatcher(url);
+            dispatcher.forward(request, response);
+        } catch (ServletException ex) {
+            log.error("UsernamePasswordAuthenticationHandler: Error returning control to " + urlDescription, ex);
+        } catch (IOException ex) {
+            log.error("UsernamePasswordAuthenticationHandler: Error returning control to " + urlDescription, ex);
+        }
+    }
 }
index bdec5bb..76ea4ad 100644 (file)
@@ -144,7 +144,7 @@ public class UsernamePasswordAuthenticationServlet extends HttpServlet {
         if (!(o instanceof String)) {
             log.error("UsernamePasswordAuthenticationServlet: Unable to authenticate user - Invalid JAAS configuration name specified: " + o.toString());
             
-            loginContext.setAuthenticationOK(false);
+            loginContext.setPrincipalAuthenticated(false);
             loginContext.setAuthenticationFailureMessage("Internal configuration error.");
             redirectControl(loginContext.getAuthenticationManagerURL(), "AuthenticationManager", request, response);
         }
@@ -157,9 +157,9 @@ public class UsernamePasswordAuthenticationServlet extends HttpServlet {
         o = request.getAttribute(LOGIN_FORM_USERNAME);
         if (!(o instanceof String)) {
             log.error("UsernamePasswordAuthenticationServlet: Login form's username is not a String.");
-            loginContext.setAuthenticationOK(false);
+            loginContext.setPrincipalAuthenticated(false);
             loginContext.setAuthenticationFailureMessage("Internal configuration error.");
-            loginContext.setAuthenticationOK(false);
+            loginContext.setPrincipalAuthenticated(false);
             loginContext.setAuthenticationFailureMessage("Internal configuration error.");
             redirectControl(loginContext.getAuthenticationManagerURL(), "AuthenticationManager", request, response);
             
@@ -169,9 +169,9 @@ public class UsernamePasswordAuthenticationServlet extends HttpServlet {
         o = request.getAttribute(LOGIN_FORM_PASSWORD);
         if (!(o instanceof String)) {
             log.error("UsernamePasswordAuthenticationServlet: Login form's password is not a String.");
-            loginContext.setAuthenticationOK(false);
+            loginContext.setPrincipalAuthenticated(false);
             loginContext.setAuthenticationFailureMessage("Internal configuration error.");
-            loginContext.setAuthenticationOK(false);
+            loginContext.setPrincipalAuthenticated(false);
             loginContext.setAuthenticationFailureMessage("Internal configuration error.");
             redirectControl(loginContext.getAuthenticationManagerURL(), "AuthenticationManager", request, response);
             
@@ -244,21 +244,21 @@ public class UsernamePasswordAuthenticationServlet extends HttpServlet {
                        log
                                        .debug("UsernamePasswordAuthenticationServlet: Authentication successful for "
                                                        + username);
-                       idpLoginCtx.setAuthenticationOK(true);
+                       idpLoginCtx.setPrincipalAuthenticated(true);
 
                        // if JAAS returned multiple usernames, only use the first one.
                        Set<Principal> principals = jaasLoginCtx.getSubject()
                                        .getPrincipals();
                        Principal[] temp = new Principal[principals.size()];
                        principals.toArray(temp);
-                       idpLoginCtx.setUserID(temp[0].getName());
+                       idpLoginCtx.setPrincipalName(temp[0].getName());
 
                } catch (LoginException ex) {
                        log
                                        .error(
                                                        "UsernamePasswordAuthenticationServlet: Error authenticating user.",
                                                        ex);
-                       idpLoginCtx.setAuthenticationOK(false);
+                       idpLoginCtx.setPrincipalAuthenticated(false);
                }
        }
 }
index edb0b32..cc8459e 100644 (file)
@@ -702,7 +702,8 @@ public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHan
         Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
         if (userSession != null) {
             queryContext.setUserSession(userSession);
-            ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
+            ServiceInformation serviceInfo = userSession.getServicesInformation().get(
+                    requestContext.getRelyingPartyId());
             if (serviceInfo != null) {
                 String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
 
index 15ee91c..2694cc9 100644 (file)
@@ -166,7 +166,7 @@ public class ShibbolethSSOProfileHandler extends AbstractSAML1ProfileHandler {
 
         Response samlResponse;
         try {
-            if (!loginContext.getAuthenticationOK()) {
+            if (!loginContext.isPrincipalAuthenticated()) {
                 requestContext.setFailureStatus(buildStatus(StatusCode.RESPONDER, null, "User failed authentication"));
                 throw new ProfileException("User failed authentication");
             }
@@ -246,7 +246,7 @@ public class ShibbolethSSOProfileHandler extends AbstractSAML1ProfileHandler {
 
         requestContext.setLoginContext(loginContext);
 
-        requestContext.setPrincipalName(loginContext.getUserID());
+        requestContext.setPrincipalName(loginContext.getPrincipalName());
 
         requestContext.setPrincipalAuthenticationMethod(loginContext.getAuthenticationMethod());
 
index d22c5ef..c50da3e 100644 (file)
@@ -548,7 +548,8 @@ public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHan
         Session userSession = getSessionManager().getSession(getUserSessionId(requestContext.getProfileRequest()));
         if (userSession != null) {
             queryContext.setUserSession(userSession);
-            ServiceInformation serviceInfo = userSession.getServiceInformation(requestContext.getRelyingPartyId());
+            ServiceInformation serviceInfo = userSession.getServicesInformation().get(
+                    requestContext.getRelyingPartyId());
             if (serviceInfo != null) {
                 String principalAuthenticationMethod = serviceInfo.getAuthenticationMethod().getAuthenticationMethod();
 
index 3142970..2804083 100644 (file)
@@ -232,7 +232,7 @@ public class SSOProfileHandler extends AbstractSAML2ProfileHandler {
 
         Response samlResponse;
         try {
-            if (!loginContext.getAuthenticationOK()) {
+            if (!loginContext.isPrincipalAuthenticated()) {
                 requestContext
                         .setFailureStatus(buildStatus(StatusCode.RESPONDER_URI, StatusCode.AUTHN_FAILED_URI, null));
                 throw new ProfileException("User failed authentication");
index 0439444..f209dd7 100644 (file)
@@ -43,4 +43,11 @@ public interface AuthenticationMethodInformation {
      * @return duration of this authentication method
      */
     public long getAuthenticationDuration();
+
+    /**
+     * Gets whether this authentication method has expired and is not longer valid for use in constructing new sessions.
+     * 
+     * @return whether this authentication method has expired
+     */
+    public boolean isExpired();
 }
\ No newline at end of file
index a93e4cb..a497e5d 100644 (file)
@@ -17,7 +17,6 @@
 package edu.internet2.middleware.shibboleth.idp.session;
 
 import org.joda.time.DateTime;
-import org.opensaml.saml2.core.NameID;
 
 /**
  * Information about a service a user has logged in to.
@@ -32,11 +31,11 @@ public interface ServiceInformation {
     public String getEntityID();
 
     /**
-     * Gets the time the user authenticated to the service.
+     * Gets the time the user logged in to the service.
      * 
-     * @return time the user authenticated to the service
+     * @return time the user logged in to the service
      */
-    public DateTime getAuthenticationInstant();
+    public DateTime getLoginInstant();
 
     /**
      * Gets the authentication method used to log into the service.
@@ -44,11 +43,4 @@ public interface ServiceInformation {
      * @return authentication method used to log into the service
      */
     public AuthenticationMethodInformation getAuthenticationMethod();
-
-    /**
-     * Gets the NameID used for the subject/user with this service.
-     * 
-     * @return NameID used for the subject/user with this service
-     */
-    public NameID getSubjectNameID();
 }
\ No newline at end of file
index 4613187..e77bb33 100644 (file)
 
 package edu.internet2.middleware.shibboleth.idp.session;
 
-import java.util.List;
+import java.util.Map;
 
 /**
  * Session information for user logged into the IdP.
  */
 public interface Session extends edu.internet2.middleware.shibboleth.common.session.Session {
-    
+
     /** Name of the HttpSession attribute a users Shibboleth session Id is bound to. */
     public static final String HTTP_SESSION_BINDING_ATTRIBUTE = "ShibbolethSessionId";
 
@@ -31,21 +31,12 @@ public interface Session extends edu.internet2.middleware.shibboleth.common.sess
      * 
      * @return methods by which the user has authenticated to the IdP
      */
-    public List<AuthenticationMethodInformation> getAuthenticationMethods();
-
-    /**
-     * Gets the information for a service a user is logged into.
-     * 
-     * @param entityId ID of the service
-     * 
-     * @return information for a service a user is logged into or null if the user is not logged into the given service
-     */
-    public ServiceInformation getServiceInformation(String entityId);
+    public Map<String, AuthenticationMethodInformation> getAuthenticationMethods();
 
     /**
      * Gets the services the user has logged in to.
      * 
      * @return services the user has logged in to
      */
-    public List<ServiceInformation> getServicesInformation();
+    public Map<String, ServiceInformation> getServicesInformation();
 }
\ No newline at end of file
index 136593b..017edda 100644 (file)
@@ -20,94 +20,74 @@ import org.joda.time.DateTime;
 
 import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
 
-
 /**
  * Information about an authentication method employed by a user.
  */
 public class AuthenticationMethodInformationImpl implements AuthenticationMethodInformation {
-    
-    /** The authentication method (a URI) */
+
+    /** The authentication method (a URI). */
     private String authenticationMethod;
-    
-    /** The timestamp at which authentication occurred */
+
+    /** The timestamp at which authentication occurred. */
     private DateTime authenticationInstant;
-    
-    /** The lifetime of the authentication method */
+
+    /** The lifetime of the authentication method. */
     private long authenticationDuration;
-    
-    
-    /**
-     * Default constructor
-     *
-     * @param authenticationMethod The unique identifier for the authentication method.
-     * @param authenticationInstant The time the user authenticated with this member.
-     * @param authenticationDuration The duration of this authentication method.
-     */
-    public AuthenticationMethodInformationImpl(final String authenticationMethod,
-           final DateTime authenticationInstant, long authenticationDuration) {
-       
-       if (authenticationMethod == null || authenticationInstant == null
-               || authenticationDuration < 0) {
-           return;
-       }
-       
-       this.authenticationMethod = authenticationMethod;
-       this.authenticationInstant = authenticationInstant;
-       this.authenticationDuration = authenticationDuration;
-    }
-    
-    
+
+    /** Time when this method expires. */
+    private DateTime expirationInstant;
+
     /**
-     * "Cloning" constructor.
-     *
-     * @param methodInfo The {@link AuthenticationMethodInfo} to duplicate.
+     * Default constructor.
+     * 
+     * @param method The unique identifier for the authentication method.
+     * @param instant The time the user authenticated with this member.
+     * @param duration The duration of this authentication method.
      */
-    public AuthenticationMethodInformationImpl(final AuthenticationMethodInformation methodInfo) {
-       
-       if (methodInfo == null) {
-           return;
-       }
-       
-       this.authenticationMethod = methodInfo.getAuthenticationMethod();
-       this.authenticationInstant = methodInfo.getAuthenticationInstant();
-       this.authenticationDuration = methodInfo.getAuthenticationDuration();
+    public AuthenticationMethodInformationImpl(String method, DateTime instant, long duration) {
+
+        if (method == null || instant == null || duration < 0) {
+            throw new IllegalArgumentException("Authentication method, instant, and duration may not be null");
+        }
+
+        authenticationMethod = method;
+        authenticationInstant = instant;
+        authenticationDuration = duration;
+        expirationInstant = instant.plus(duration);
     }
-    
-    
+
     /** {@inheritDoc} */
     public String getAuthenticationMethod() {
-       return this.authenticationMethod;
+        return authenticationMethod;
     }
-    
-    
+
     /** {@inheritDoc} */
     public DateTime getAuthenticationInstant() {
-       return this.authenticationInstant;
+        return authenticationInstant;
     }
-    
-    
+
     /** {@inheritDoc} */
     public long getAuthenticationDuration() {
-       return this.authenticationDuration;
+        return authenticationDuration;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isExpired() {
+        return expirationInstant.isBeforeNow();
     }
-    
     
     /** {@inheritDoc} */
+    public int hashCode() {
+        return authenticationMethod.hashCode();
+    }
+
+    /** {@inheritDoc} */
     public boolean equals(Object obj) {
-       
-       if (!(obj instanceof AuthenticationMethodInformation)) {
-           return false;
-       }
-       
-       AuthenticationMethodInformation amInfo = (AuthenticationMethodInformation)obj;
-       
-       if (this.getAuthenticationMethod().equals(amInfo.getAuthenticationMethod())
-           && this.getAuthenticationInstant().equals(amInfo.getAuthenticationInstant())
-           && this.getAuthenticationDuration() == amInfo.getAuthenticationDuration()) {
-           
-           return true;
-       } else {
-           return false;
-       }
+        if (!(obj instanceof AuthenticationMethodInformation)) {
+            return false;
+        }
+
+        AuthenticationMethodInformation amInfo = (AuthenticationMethodInformation) obj;
+        return authenticationMethod.equals(amInfo.getAuthenticationMethod());
     }
-}
+}
\ No newline at end of file
index c8e5dc3..4cefda0 100644 (file)
 
 package edu.internet2.middleware.shibboleth.idp.session.impl;
 
+import org.joda.time.DateTime;
+
 import edu.internet2.middleware.shibboleth.idp.session.AuthenticationMethodInformation;
 import edu.internet2.middleware.shibboleth.idp.session.ServiceInformation;
 
-import org.joda.time.DateTime;
-import org.opensaml.saml2.core.NameID;
-
 /**
  * Information about a service a user has logged in to.
  */
@@ -36,42 +35,17 @@ public class ServiceInformationImpl implements ServiceInformation {
     /** Authentication method used to authenticate the user to the service. */
     private AuthenticationMethodInformation methodInfo;
 
-    /** Name ID provided to the service. */
-    private NameID nameId;
-
     /**
      * Default constructor.
      * 
-     * @param entityID The unique identifier for the service.
-     * @param authenticationInstant The time the user authenticated to the service.
-     * @param methodInfo The authentication method used to log into the service.
-     * @param nameId The {@link NameID} used for the subject/user with this service.
-     * 
+     * @param id unique identifier for the service.
+     * @param loginInstant time the user logged in to the service.
+     * @param method authentication method used to log into the service.
      */
-    public ServiceInformationImpl(String entityID, DateTime authenticationInstant, AuthenticationMethodInformation methodInfo,
-            NameID nameId) {
-
-        this.entityID = entityID;
-        this.authenticationInstant = authenticationInstant;
-        this.methodInfo = methodInfo;
-        this.nameId = nameId;
-    }
-
-    /**
-     * Cloning constructor.
-     * 
-     * @param serviceInfo The ServiceInformation instance to duplicate.
-     */
-    public ServiceInformationImpl(final ServiceInformation serviceInfo) {
-
-        if (serviceInfo == null) {
-            return;
-        }
-
-        this.entityID = serviceInfo.getEntityID();
-        this.authenticationInstant = serviceInfo.getAuthenticationInstant();
-        this.methodInfo = serviceInfo.getAuthenticationMethod();
-        this.nameId = serviceInfo.getSubjectNameID();
+    public ServiceInformationImpl(String id, DateTime loginInstant, AuthenticationMethodInformation method) {
+        entityID = id;
+        authenticationInstant = loginInstant;
+        methodInfo = method;
     }
 
     /** {@inheritDoc} */
@@ -80,7 +54,7 @@ public class ServiceInformationImpl implements ServiceInformation {
     }
 
     /** {@inheritDoc} */
-    public DateTime getAuthenticationInstant() {
+    public DateTime getLoginInstant() {
         return authenticationInstant;
     }
 
@@ -90,8 +64,8 @@ public class ServiceInformationImpl implements ServiceInformation {
     }
 
     /** {@inheritDoc} */
-    public NameID getSubjectNameID() {
-        return nameId;
+    public int hashCode() {
+        return entityID.hashCode();
     }
 
     /** {@inheritDoc} */
@@ -101,13 +75,6 @@ public class ServiceInformationImpl implements ServiceInformation {
         }
 
         ServiceInformation si = (ServiceInformation) obj;
-        if (this.getEntityID().equals(si.getEntityID())
-                && this.getAuthenticationInstant().equals(si.getAuthenticationInstant())
-                && this.getSubjectNameID().equals(si.getSubjectNameID())) {
-
-            return true;
-        }
-        
-        return false;
+        return entityID.equals(si.getEntityID());
     }
 }
\ No newline at end of file
index ffebd4b..56d2a23 100644 (file)
@@ -17,9 +17,7 @@
 package edu.internet2.middleware.shibboleth.idp.session.impl;
 
 import java.net.InetAddress;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import edu.internet2.middleware.shibboleth.common.session.impl.AbstractSession;
@@ -31,15 +29,15 @@ import edu.internet2.middleware.shibboleth.idp.session.Session;
  * Session information for user logged into the IdP.
  */
 public class SessionImpl extends AbstractSession implements Session {
-    
+
     /** Serial version UID. */
     private static final long serialVersionUID = 2927868242208211623L;
 
     /** The list of methods used to authentictate the user. */
-    private List<AuthenticationMethodInformation> authnMethods;
+    private HashMap<String, AuthenticationMethodInformation> authnMethods;
 
     /** The list of services to which the user has logged in. */
-    private Map<String, ServiceInformation> servicesInformation;
+    private HashMap<String, ServiceInformation> servicesInformation;
 
     /**
      * Default constructor.
@@ -50,27 +48,22 @@ public class SessionImpl extends AbstractSession implements Session {
     public SessionImpl(InetAddress presenter, String principal) {
         super(presenter, principal);
 
-        authnMethods = new ArrayList<AuthenticationMethodInformation>();
+        authnMethods = new HashMap<String, AuthenticationMethodInformation>();
         servicesInformation = new HashMap<String, ServiceInformation>();
     }
 
     /** {@inheritDoc} */
-    public List<AuthenticationMethodInformation> getAuthenticationMethods() {
+    public Map<String, AuthenticationMethodInformation> getAuthenticationMethods() {
         return authnMethods;
     }
-    
+
     /** {@inheritDoc} */
     public ServiceInformation getServiceInformation(String entityId) {
         return servicesInformation.get(entityId);
     }
 
     /** {@inheritDoc} */
-    public List<ServiceInformation> getServicesInformation() {
-        ArrayList<ServiceInformation> info = new ArrayList<ServiceInformation>();
-        for(Map.Entry<String, ServiceInformation> entry : servicesInformation.entrySet()){
-            info.add(entry.getValue());
-        }
-        
-        return info;
+    public Map<String, ServiceInformation> getServicesInformation() {
+        return servicesInformation;
     }
 }
\ No newline at end of file
index ff4e07f..c70db6d 100644 (file)
@@ -29,6 +29,8 @@ import edu.internet2.middleware.shibboleth.idp.session.Session;
 
 /**
  * Manager of IdP sessions.
+ * 
+ * TODO change session map to use storage api
  */
 public class SessionManagerImpl implements SessionManager<Session>, ApplicationContextAware {