Have each login handler report the authentication method it performed and document...
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Mon, 10 Oct 2011 15:49:17 +0000 (15:49 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Mon, 10 Oct 2011 15:49:17 +0000 (15:49 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/branches/REL_2@3073 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

doc/RELEASE-NOTES.txt
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/LoginHandler.java
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/IPAddressLoginHandler.java
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/RemoteUserAuthServlet.java
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/UsernamePasswordLoginServlet.java

index 4997bec..c638b7c 100644 (file)
@@ -3,6 +3,7 @@ Changes in Release 2.3.4
 [SIDP-516] - Example login.jsp / Usage of label tag
 [SIDP-513] - idpui taglib could look for more languages matches
 [SIDP-514] - Alt text for IdP Logos is not esapiEncoder.encodeForHTMLAttribute
+[SIDP-519] - Switching between multiple login handlers cause first context to be sticky in Shib-Authentication-Method
 [SIDP-520] - Ipad/iOS devices will auto capitalize text entered into the IdP login screen, which can cause errors. Adding an HTML element will prevent that
 [SIDP-522] - supplied examples shouldn't promote federation URIs as relying parties
 [SIDP-523] - Add access to inbound AuthnRequest
index cfe7884..ab82545 100644 (file)
@@ -47,11 +47,16 @@ import javax.servlet.http.HttpServletResponse;
  * {@link javax.security.auth.Subject} within the {@link edu.internet2.middleware.shibboleth.idp.session.Session}.</li>
  * </ul>
  * 
- * The handler <strong>MAY</strong> also:
+ * The handler <strong>SHOULD</strong> also:
  * <ul>
  * <li>Bind a URI string, representing the authentication method actually used, to a request attribute identified by
- * {@link #AUTHENTICATION_METHOD_KEY}. This may be used if a handler is capable of performing multiple types of
- * authentication.</li>
+ * {@link #AUTHENTICATION_METHOD_KEY}. Failure to do so may lead to a situation where one authentication method is 
+ * started but a user switches to a weaker one in mid-process.  Without the login handler explicitly setting the 
+ * method, the first method that is started is what will be reported to the relying party.</li>
+ * </ul>
+ * 
+ * The handler <strong>MAY</strong> also:
+ * <ul>
  * <li>Bind an error message, if an error occurred during authentication to the request attribute identified by
  * {@link LoginHandler#AUTHENTICATION_ERROR_KEY}.</li>
  * <li>Bind a {@link AuthenticationException}, if an exception occurred during authentication to the request attribute
index 6901cf8..25132b1 100644 (file)
@@ -25,6 +25,7 @@ import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.opensaml.saml2.core.AuthnContext;
 import org.opensaml.xml.util.DatatypeHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,7 +54,15 @@ public class IPAddressLoginHandler extends AbstractLoginHandler {
     /** Whether a user is "authenticated" if their IP address is within a configured IP range. */
     private boolean ipInRangeIsAuthenticated;
 
-    public IPAddressLoginHandler(String user, List<IPRange> ranges, boolean ipInRangeIsAuthenticated) {
+    /**
+     * Constructor.
+     * 
+     * @param user username to return upon successful "authentication"
+     * @param ranges range of IP addresses specified
+     * @param isIpInRangeAuthenticated whether the specified IP address range represent those that are authenticated or
+     *            those that are not
+     */
+    public IPAddressLoginHandler(String user, List<IPRange> ranges, boolean isIpInRangeAuthenticated) {
         authenticatedUser = DatatypeHelper.safeTrimOrNullString(user);
         if (authenticatedUser == null) {
             throw new IllegalArgumentException("The authenticated user ID may not be null or empty");
@@ -64,7 +73,7 @@ public class IPAddressLoginHandler extends AbstractLoginHandler {
         }
         ipRanges = new ArrayList<IPRange>(ranges);
 
-        this.ipInRangeIsAuthenticated = ipInRangeIsAuthenticated;
+        this.ipInRangeIsAuthenticated = isIpInRangeAuthenticated;
     }
 
     /** {@inheritDoc} */
@@ -85,6 +94,7 @@ public class IPAddressLoginHandler extends AbstractLoginHandler {
             if (authenticate(clientAddress)) {
                 log.debug("Authenticated user by IP address");
                 httpRequest.setAttribute(LoginHandler.PRINCIPAL_NAME_KEY, authenticatedUser);
+                httpRequest.setAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY, AuthnContext.IP_AUTHN_CTX);
             } else {
                 log.debug("Client IP address {} failed authentication.", httpRequest.getRemoteAddr());
                 httpRequest.setAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY,
index 26a5ff8..11231d7 100644 (file)
@@ -19,11 +19,13 @@ package edu.internet2.middleware.shibboleth.idp.authn.provider;
 
 import java.io.IOException;
 
+import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.opensaml.saml2.core.AuthnContext;
 import org.opensaml.xml.util.DatatypeHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,23 +34,46 @@ import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine;
 import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
 import edu.internet2.middleware.shibboleth.idp.authn.UsernamePrincipal;
 
-/** Extracts the REMOTE_USER and places it in a request attribute to be used by the authentication engine. */
+/**
+ * Extracts the REMOTE_USER and places it in a request attribute to be used by the authentication engine.
+ * 
+ * By default, this Servlet assumes that the authentication method {@value AuthnContext#PPT_AUTHN_CTX} to be returned to
+ * the authentication engine. This can be override by setting the servlet configuration parameter
+ * {@value LoginHandler#AUTHENTICATION_METHOD_KEY}.
+ */
 public class RemoteUserAuthServlet extends HttpServlet {
 
     /** Serial version UID. */
-    private static final long serialVersionUID = -6153665874235557534L;    
+    private static final long serialVersionUID = -6153665874235557534L;
 
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(RemoteUserAuthServlet.class);
 
+    /** The authentication method returned to the authentication engine. */
+    private String authenticationMethod;
+
+    /** {@inheritDoc} */
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+
+        String method =
+                DatatypeHelper.safeTrimOrNullString(config.getInitParameter(LoginHandler.AUTHENTICATION_METHOD_KEY));
+        if (method != null) {
+            authenticationMethod = method;
+        } else {
+            authenticationMethod = AuthnContext.PPT_AUTHN_CTX;
+        }
+    }
+
     /** {@inheritDoc} */
     protected void service(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException,
             IOException {
         String principalName = DatatypeHelper.safeTrimOrNullString(httpRequest.getRemoteUser());
-        if(principalName != null){
+        if (principalName != null) {
             log.debug("Remote user identified as {} returning control back to authentication engine", principalName);
             httpRequest.setAttribute(LoginHandler.PRINCIPAL_KEY, new UsernamePrincipal(principalName));
-        }else{
+            httpRequest.setAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY, authenticationMethod);
+        } else {
             log.debug("No remote user information was present in the request");
         }
 
index de668f6..432b78f 100644 (file)
@@ -34,6 +34,7 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.opensaml.saml2.core.AuthnContext;
 import org.opensaml.xml.util.DatatypeHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -173,6 +174,11 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
 
             Subject userSubject = new Subject(false, principals, publicCredentials, privateCredentials);
             request.setAttribute(LoginHandler.SUBJECT_KEY, userSubject);
+            if(request.isSecure()){
+                request.setAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY, AuthnContext.PPT_AUTHN_CTX);
+            }else{
+                request.setAttribute(LoginHandler.AUTHENTICATION_METHOD_KEY, AuthnContext.PASSWORD_AUTHN_CTX);
+            }
         } catch (LoginException e) {
             log.debug("User authentication for " + username + " failed", e);
             throw e;