Provide flags for retaining public and private user credentials, defaults to false...
authorlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 1 Jul 2009 06:51:39 +0000 (06:51 +0000)
committerlajoie <lajoie@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 1 Jul 2009 06:51:39 +0000 (06:51 +0000)
Make UsernamePassword login handler alway retain the password as a private credential - SIDP-135

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

doc/RELEASE-NOTES.txt
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/AuthenticationEngine.java
src/main/java/edu/internet2/middleware/shibboleth/idp/authn/provider/UsernamePasswordLoginServlet.java
src/main/webapp/WEB-INF/web.xml

index 943912d..00b0e69 100644 (file)
@@ -10,6 +10,7 @@ Changes in Release 2.1.3
 [SIDP-291] - Update libs for 2.1.3 release
 [SIDP-306] - Remove ClientCertAuth rule from SAML 2 SSO SecurityPolicy in relying-party.xml
 [SIDP-310] - Change default relying-party.xml settings for SAML 2 profiles' encryptNameIds parameter from "conditional" to "never"
+[SIDP-315] - Credential provided by UsernamePasswordLogin handler as attribute
 [SIDP-318] - IdP erroneously logs many normal events as errors
 [SIDP-322] - Exception thrown when SP requests a particular authentication method that is not configured
 
index d4eb5ab..c0fc08a 100644 (file)
@@ -61,6 +61,18 @@ import edu.internet2.middleware.shibboleth.idp.session.impl.ServiceInformationIm
 /** Manager responsible for handling authentication requests. */
 public class AuthenticationEngine extends HttpServlet {
 
+    /**
+     * Name of the Servlet config init parameter that indicates whether the public credentials of a {@link Subject} are
+     * retained after authentication.
+     */
+    public static final String RETAIN_PUBLIC_CREDENTIALS = "retainSubjectsPublicCredentials";
+
+    /**
+     * Name of the Servlet config init parameter that indicates whether the private credentials of a {@link Subject} are
+     * retained after authentication.
+     */
+    public static final String RETAIN_PRIVATE_CREDENTIALS = "retainSubjectsPrivateCredentials";
+
     /** Name of the Servlet config init parameter that holds the partition name for login contexts. */
     public static final String LOGIN_CONTEXT_PARTITION_NAME_INIT_PARAM_NAME = "loginContextPartitionName";
 
@@ -91,6 +103,12 @@ public class AuthenticationEngine extends HttpServlet {
     /** ID generator. */
     private static IdentifierGenerator idGen;
 
+    /** Whether the public credentials of a {@link Subject} are retained after authentication. */
+    private boolean retainSubjectsPublicCredentials;
+
+    /** Whether the private credentials of a {@link Subject} are retained after authentication. */
+    private boolean retainSubjectsPrivateCredentials;
+
     /** Profile handler manager. */
     private IdPProfileHandlerManager handlerManager;
 
@@ -101,6 +119,20 @@ public class AuthenticationEngine extends HttpServlet {
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
 
+        String retain = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(RETAIN_PRIVATE_CREDENTIALS));
+        if (retain != null) {
+            retainSubjectsPrivateCredentials = Boolean.parseBoolean(retain);
+        } else {
+            retainSubjectsPrivateCredentials = false;
+        }
+
+        retain = DatatypeHelper.safeTrimOrNullString(config.getInitParameter(RETAIN_PUBLIC_CREDENTIALS));
+        if (retain != null) {
+            retainSubjectsPublicCredentials = Boolean.parseBoolean(retain);
+        } else {
+            retainSubjectsPublicCredentials = false;
+        }
+
         String handlerManagerId = config.getInitParameter("handlerManagerId");
         if (DatatypeHelper.isEmpty(handlerManagerId)) {
             handlerManagerId = "shibboleth.HandlerManager";
@@ -317,7 +349,8 @@ public class AuthenticationEngine extends HttpServlet {
             } else {
                 possibleLoginHandlers.remove(AuthnContext.PREVIOUS_SESSION_AUTHN_CTX);
                 if (possibleLoginHandlers.isEmpty()) {
-                    LOG.info("No authentication mechanism available for use with relying party '{}'", loginContext.getRelyingPartyId());
+                    LOG.info("No authentication mechanism available for use with relying party '{}'", loginContext
+                            .getRelyingPartyId());
                     throw new AuthenticationException();
                 }
                 Entry<String, LoginHandler> chosenLoginHandler = possibleLoginHandlers.entrySet().iterator().next();
@@ -577,7 +610,7 @@ public class AuthenticationEngine extends HttpServlet {
     protected void validateSuccessfulAuthentication(LoginContext loginContext, HttpServletRequest httpRequest,
             String authenticationMethod) throws AuthenticationException {
         LOG.debug("Validating authentication was performed successfully");
-        
+
         String errorMessage = DatatypeHelper.safeTrimOrNullString((String) httpRequest
                 .getAttribute(LoginHandler.AUTHENTICATION_ERROR_KEY));
         if (errorMessage != null) {
@@ -699,7 +732,11 @@ public class AuthenticationEngine extends HttpServlet {
     }
 
     /**
-     * Merges the principals and public and private credentials from two subjects into a new subject.
+     * Merges the two {@link Subject}s in to a new {@link Subject}. The new subjects contains all the {@link Principal}s
+     * from both subjects. If {@link #retainSubjectsPrivateCredentials} is true then the new subject will contain all
+     * the private credentials from both subjects, if not the new subject will not contain private credentials. If
+     * {@link #retainSubjectsPublicCredentials} is true then the new subject will contain all the public credentials
+     * from both subjects, if not the new subject will not contain public credentials.
      * 
      * @param subject1 first subject to merge, may be null
      * @param subject2 second subject to merge, may be null
@@ -710,7 +747,7 @@ public class AuthenticationEngine extends HttpServlet {
         if (subject1 == null && subject2 == null) {
             return new Subject();
         }
-        
+
         if (subject1 == null) {
             return subject2;
         }
@@ -724,12 +761,18 @@ public class AuthenticationEngine extends HttpServlet {
         principals.addAll(subject2.getPrincipals());
 
         Set<Object> publicCredentials = new HashSet<Object>(3);
-        publicCredentials.addAll(subject1.getPublicCredentials());
-        publicCredentials.addAll(subject2.getPublicCredentials());
+        if (retainSubjectsPublicCredentials) {
+            LOG.debug("Merging in subjects public credentials");
+            publicCredentials.addAll(subject1.getPublicCredentials());
+            publicCredentials.addAll(subject2.getPublicCredentials());
+        }
 
         Set<Object> privateCredentials = new HashSet<Object>(3);
-        privateCredentials.addAll(subject1.getPrivateCredentials());
-        privateCredentials.addAll(subject2.getPrivateCredentials());
+        if (retainSubjectsPrivateCredentials) {
+            LOG.debug("Merging in subjects private credentials");
+            privateCredentials.addAll(subject1.getPrivateCredentials());
+            privateCredentials.addAll(subject2.getPrivateCredentials());
+        }
 
         return new Subject(false, principals, publicCredentials, privateCredentials);
     }
index 48a8fbb..4c37a34 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 [University Corporation for Advanced Internet Development, Inc.
+ * 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.
@@ -44,8 +44,8 @@ import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;
 import edu.internet2.middleware.shibboleth.idp.authn.UsernamePrincipal;
 
 /**
- * This Servlet should be protected by a filter which populates REMOTE_USER. The Servlet will then set the remote user
- * field in a LoginContext.
+ * This Servlet authenticates a user via JAAS. The user's credential is always added to the returned {@link Subject} as
+ * a {@link UsernamePasswordCredential} within the subject's private credentials.
  */
 public class UsernamePasswordLoginServlet extends HttpServlet {
 
@@ -55,9 +55,6 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(UsernamePasswordLoginServlet.class);
 
-    /** Whether to store a user's credentials within the {@link Subject}. */
-    private boolean storeCredentialsInSubject;
-
     /** Name of JAAS configuration used to authenticate users. */
     private String jaasConfigName = "ShibUserPassAuth";
 
@@ -72,9 +69,6 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
 
     /** Parameter name to indicate login failure. */
     private final String failureParam = "loginFailed";
-    
-    /** Parameter name to indicate the login credentials should be stored in the Subject private credential set. */
-    private final String storeCredentials = "storeCredentialsInSubject";
 
     /** HTTP request parameter containing the user name. */
     private final String usernameAttribute = "j_username";
@@ -85,21 +79,17 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
     /** {@inheritDoc} */
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
-        
+
         if (getInitParameter(jaasInitParam) != null) {
             jaasConfigName = getInitParameter(jaasInitParam);
         }
-        
+
         if (getInitParameter(loginPageInitParam) != null) {
             loginPage = getInitParameter(loginPageInitParam);
         }
-        if(!loginPage.startsWith("/")){
+        if (!loginPage.startsWith("/")) {
             loginPage = "/" + loginPage;
         }
-        
-        if(getInitParameter(storeCredentials) != null){
-            storeCredentialsInSubject = Boolean.parseBoolean(getInitParameter(storeCredentials));
-        }
     }
 
     /** {@inheritDoc} */
@@ -131,26 +121,26 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
      */
     protected void redirectToLoginPage(HttpServletRequest request, HttpServletResponse response,
             List<Pair<String, String>> queryParams) {
-       
+
         String requestContext = DatatypeHelper.safeTrimOrNullString(request.getContextPath());
-        if(requestContext == null){
+        if (requestContext == null) {
             requestContext = "/";
         }
         request.setAttribute("actionUrl", requestContext + request.getServletPath());
 
-        if(queryParams != null){
-            for(Pair<String, String> param : queryParams){
+        if (queryParams != null) {
+            for (Pair<String, String> param : queryParams) {
                 request.setAttribute(param.getFirst(), param.getSecond());
             }
         }
-        
+
         try {
             request.getRequestDispatcher(loginPage).forward(request, response);
             log.debug("Redirecting to login page {}", loginPage);
         } catch (IOException ex) {
             log.error("Unable to redirect to login page.", ex);
-        }catch (ServletException ex){
-            log.error("Unable to redirect to login page.", ex);            
+        } catch (ServletException ex) {
+            log.error("Unable to redirect to login page.", ex);
         }
     }
 
@@ -187,9 +177,7 @@ public class UsernamePasswordLoginServlet extends HttpServlet {
             Set<Object> publicCredentials = loginSubject.getPublicCredentials();
 
             Set<Object> privateCredentials = loginSubject.getPrivateCredentials();
-            if (storeCredentialsInSubject) {
-                privateCredentials.add(new UsernamePasswordCredential(username, password));
-            }
+            privateCredentials.add(new UsernamePasswordCredential(username, password));
 
             Subject userSubject = new Subject(false, principals, publicCredentials, privateCredentials);
             request.setAttribute(LoginHandler.SUBJECT_KEY, userSubject);
index c7ace13..b188e6f 100644 (file)
     <servlet-mapping>
         <servlet-name>ProfileRequestDispatcher</servlet-name>
         <url-pattern>/profile/*</url-pattern>
-    </servlet-mapping>
-    
-    <servlet>
-        <servlet-name>Status</servlet-name>
-        <servlet-class>edu.internet2.middleware.shibboleth.idp.StatusServlet</servlet-class>
-        <load-on-startup>2</load-on-startup>
-    </servlet>
-
-    <servlet-mapping>
-        <servlet-name>Status</servlet-name>
-        <url-pattern>/status</url-pattern>
-    </servlet-mapping>
-    
-    <!-- Send request to the EntityID to the SAML metadata handler. -->
-    <servlet>
-        <servlet-name>shibboleth_jsp</servlet-name>
-        <jsp-file>/shibboleth.jsp</jsp-file>
-    </servlet>
-
-    <servlet-mapping>
-        <servlet-name>shibboleth_jsp</servlet-name>
-        <url-pattern>/shibboleth</url-pattern>
     </servlet-mapping> 
 
     <!-- Authentication Engine Entry Point -->
     <servlet>
         <servlet-name>AuthenticationEngine</servlet-name>
         <servlet-class>edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine</servlet-class>
+        
+        <!-- Whether public credentials returned by a login handler are retained in the subject. -->
+        <!--
+        <init-param>
+            <param-name>retainSubjectsPublicCredentials</param-name>
+            <param-value>false</param-value>
+        </init-param>
+        -->
+        
+        <!-- Whether private credentials returned by a login handler are retained in the subject. -->
+        <!--
+        <init-param>
+            <param-name>retainSubjectsPrivateCredentials</param-name>
+            <param-value>false</param-value>
+        </init-param>
+        -->
+        
         <load-on-startup>2</load-on-startup>
+        
     </servlet>
 
     <servlet-mapping>
         <url-pattern>/Authn/UserPassword</url-pattern>
     </servlet-mapping>
     
+    <!-- Servlet for displaying IdP status. -->
+    <servlet>
+        <servlet-name>Status</servlet-name>
+        <servlet-class>edu.internet2.middleware.shibboleth.idp.StatusServlet</servlet-class>
+        <load-on-startup>2</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Status</servlet-name>
+        <url-pattern>/status</url-pattern>
+    </servlet-mapping>
+    
+        
+    <!-- Send request to the EntityID to the SAML metadata handler. -->
+    <servlet>
+        <servlet-name>shibboleth_jsp</servlet-name>
+        <jsp-file>/shibboleth.jsp</jsp-file>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>shibboleth_jsp</servlet-name>
+        <url-pattern>/shibboleth</url-pattern>
+    </servlet-mapping>
+    
     <error-page>
         <error-code>500</error-code>
         <location>/error.jsp</location>