[gatein-commits] gatein SVN: r8071 - epp/portal/branches/EPP_5_2_Branch/component/web/security/src/main/java/org/exoplatform/web/security.

do-not-reply at jboss.org do-not-reply at jboss.org
Tue Nov 15 04:22:59 EST 2011


Author: mposolda
Date: 2011-11-15 04:22:58 -0500 (Tue, 15 Nov 2011)
New Revision: 8071

Modified:
   epp/portal/branches/EPP_5_2_Branch/component/web/security/src/main/java/org/exoplatform/web/security/PortalLoginModule.java
Log:
JBEPP-729 - Problem with credentials in HTTP session

Modified: epp/portal/branches/EPP_5_2_Branch/component/web/security/src/main/java/org/exoplatform/web/security/PortalLoginModule.java
===================================================================
--- epp/portal/branches/EPP_5_2_Branch/component/web/security/src/main/java/org/exoplatform/web/security/PortalLoginModule.java	2011-11-15 09:05:45 UTC (rev 8070)
+++ epp/portal/branches/EPP_5_2_Branch/component/web/security/src/main/java/org/exoplatform/web/security/PortalLoginModule.java	2011-11-15 09:22:58 UTC (rev 8071)
@@ -22,6 +22,9 @@
 import org.exoplatform.container.ExoContainer;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
+import org.exoplatform.services.security.Authenticator;
+import org.exoplatform.services.security.Identity;
+import org.exoplatform.services.security.UsernameCredential;
 import org.exoplatform.services.security.jaas.AbstractLoginModule;
 import org.exoplatform.web.login.InitiateLoginServlet;
 import org.gatein.wci.security.Credentials;
@@ -34,14 +37,9 @@
 import java.lang.reflect.Method;
 
 /**
- * A login module implementation that relies on the token store to check the
- * password validity. If the token store provides a valid {@link Credentials}
- * value then password stacking is used and the two entries are added in the
- * shared state map. The first entry is keyed by
- * <code>javax.security.auth.login.name</code> and contains the
- * {@link Credentials#getUsername()} value, the second entry is keyed by
- * <code>javax.security.auth.login.password</code> and contains the
- * {@link Credentials#getPassword()} ()} value.
+ * A login module implementation that is used to handle reauthentication of client with same HTTP session on various cluster nodes.
+ * After login of user on cluster node is attribute "authenticatedCredentials" added to HTTP session in method {@link #commit()}.
+ * Other cluster nodes can than read these credentials in method {@link #login()}, and can reuse them to relogin.
  * 
  * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
  * @version $Revision$
@@ -58,23 +56,21 @@
    static
    {
       Method getContext = null;
-      if (isClusteredSSO())
+
+      log.debug("About to configure PortalLoginModule");
+      try
       {
-         log.debug("About to configure clustered SSO");
-         try
-         {
-            Class<?> policyContextClass = Thread.currentThread().getContextClassLoader().loadClass("javax.security.jacc.PolicyContext");
-            getContext = policyContextClass.getDeclaredMethod("getContext", String.class);
-         }
-         catch (ClassNotFoundException ignore)
-         {
-            log.debug("JACC not found ignoring it", ignore);
-         }
-         catch (Exception e)
-         {
-            log.error("Could not obtain JACC get context method", e);
-         }
+         Class<?> policyContextClass = Thread.currentThread().getContextClassLoader().loadClass("javax.security.jacc.PolicyContext");
+         getContext = policyContextClass.getDeclaredMethod("getContext", String.class);
       }
+      catch (ClassNotFoundException ignore)
+      {
+         log.debug("JACC not found ignoring it", ignore);
+      }
+      catch (Exception e)
+      {
+         log.error("Could not obtain JACC get context method", e);
+      }
 
       //
       getContextMethod = getContext;
@@ -82,61 +78,58 @@
 
    public static final String AUTHENTICATED_CREDENTIALS = "authenticatedCredentials";
 
+   private static final String LOGIN_ON_DIFFERENT_NODE = "PortalLoginModule.loginOnDifferentNode";
+
    /**
     * @see javax.security.auth.spi.LoginModule#login()
     */
    @SuppressWarnings("unchecked")
    public boolean login() throws LoginException
    {
-
-      Callback[] callbacks = new Callback[2];
-      callbacks[0] = new NameCallback("Username");
-      callbacks[1] = new PasswordCallback("Password", false);
-
-      try
+      if (getContextMethod != null)
       {
-         callbackHandler.handle(callbacks);
-         String password = new String(((PasswordCallback)callbacks[1]).getPassword());
+         Credentials authCredentials = null;
 
-         Credentials c = null;
-         
-         //
-         // For clustered config check credentials stored and propagated in session. This won't work in tomcat because
-         // of lack of JACC PolicyContext so the code must be a bit defensive
-         if (getContextMethod != null && password.startsWith(InitiateLoginServlet.COOKIE_NAME))
+         try
          {
-            HttpServletRequest request;
-            try
+            HttpServletRequest request = (HttpServletRequest)getContextMethod.invoke(null, "javax.servlet.http.HttpServletRequest");
+            authCredentials = (Credentials)request.getSession().getAttribute(AUTHENTICATED_CREDENTIALS);
+
+            // If authenticated credentials were presented in HTTP session, it means that we were already logged on different cluster node
+            // with this HTTP session. We don't need to validate password again in this case (We don't have password anyway)
+            if (authCredentials != null)
             {
-               request = (HttpServletRequest)getContextMethod.invoke(null, "javax.servlet.http.HttpServletRequest");
-               Object o = request.getSession().getAttribute(AUTHENTICATED_CREDENTIALS);
-
-               if (o instanceof Credentials)
+               Authenticator authenticator = (Authenticator)getContainer().getComponentInstanceOfType(Authenticator.class);
+               if (authenticator == null)
                {
-                 c = (Credentials) o;
+                  throw new LoginException("No Authenticator component found, check your configuration");
                }
+
+               String username = authCredentials.getUsername();
+               Identity identity = authenticator.createIdentity(username);
+
+               sharedState.put("exo.security.identity", identity);
+               sharedState.put("javax.security.auth.login.name", username);
+
+               subject.getPublicCredentials().add(new UsernameCredential(username));
+
+               // Add empty password to subject and remove password key, so that SharedStateLoginModule won't be processed
+               subject.getPrivateCredentials().add("");
+               sharedState.remove("javax.security.auth.login.password");
+
+               // Add flag that we were logged with real password on different cluster node. Not on this node.
+               sharedState.put(LOGIN_ON_DIFFERENT_NODE, true);
             }
-            catch(Throwable e)
-            {
-               log.error(this,e);
-               log.error("LoginModule error. Turn off session credentials checking with proper configuration option of " +
-                  "LoginModule set to false");
-            }
          }
-
-         if (c != null)
+         catch(Exception e)
          {
-           sharedState.put("javax.security.auth.login.name", c.getUsername());
-           sharedState.put("javax.security.auth.login.password", c.getPassword());
+            log.error(this, e);
+            LoginException le = new LoginException(e.getMessage());
+            le.initCause(e);
+            throw le;
          }
-         return true;
       }
-      catch (Exception e)
-      {
-         LoginException le = new LoginException();
-         le.initCause(e);
-         throw le;
-      }
+      return true;
    }
 
    /**
@@ -144,21 +137,22 @@
     */
    public boolean commit() throws LoginException
    {
-
+      // Add authenticated credentials to session only if we were logged on this host with "real" credentials
       if (getContextMethod != null &&
          sharedState.containsKey("javax.security.auth.login.name") &&
-         sharedState.containsKey("javax.security.auth.login.password"))
+         sharedState.containsKey("javax.security.auth.login.password") &&
+         sharedState.get(LOGIN_ON_DIFFERENT_NODE) == null)
       {
          String uid = (String)sharedState.get("javax.security.auth.login.name");
-         String pass = (String)sharedState.get("javax.security.auth.login.password");
 
-         Credentials wc = new Credentials(uid, pass);
+         Credentials wc = new Credentials(uid, "");
 
          HttpServletRequest request = null;
          try
          {
             request = (HttpServletRequest)getContextMethod.invoke(null, "javax.servlet.http.HttpServletRequest");
             request.getSession().setAttribute(AUTHENTICATED_CREDENTIALS, wc);
+            handleCredentialsRemoving(request);
          }
          catch(Exception e)
          {
@@ -196,4 +190,15 @@
    {
       return ExoContainer.getProfiles().contains("cluster");
    }
+
+   /**
+    * Remove credentials of authenticated user from HTTP session.
+    *
+    * @param request httpRequest
+    */
+   protected void handleCredentialsRemoving(HttpServletRequest request)
+   {
+      // TODO: We can't remove credentials from HTTP session right now because WSRP-Security relies on it. See method WSSecurityCredentialHelper.handleRequest
+      // request.getSession().removeAttribute(Credentials.CREDENTIALS);
+   }
 }



More information about the gatein-commits mailing list