[jboss-cvs] JBossAS SVN: r66612 - in branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat: security/login and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Oct 31 10:22:51 EDT 2007


Author: sguilhen at redhat.com
Date: 2007-10-31 10:22:51 -0400 (Wed, 31 Oct 2007)
New Revision: 66612

Added:
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/ExtendedSingleSignOn.java
Modified:
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/ClusteredSingleSignOn.java
Log:
JBAS-4424: Added the ExtendedSingleSignOn class, that exposes some methods of the SingleSignOn valve as public, allowing the WebAuthentication to provide sso behavior to users performing programmatic web authentication. 



Added: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/ExtendedSingleSignOn.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/ExtendedSingleSignOn.java	                        (rev 0)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/ExtendedSingleSignOn.java	2007-10-31 14:22:51 UTC (rev 66612)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.security;
+
+import java.security.Principal;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.authenticator.SingleSignOn;
+
+/**
+ * <p>
+ * An extension of the <code>SingleSignOn</code> valve that exposes some protected methods of
+ * the superclass as <code>public</code>, allowing the <code>WebAuthentication</code> class
+ * to delegate single sign-on behaviour to this valve.
+ * </p>
+ * 
+ * @author sguilhen at redhat.com
+ */
+public class ExtendedSingleSignOn extends SingleSignOn
+{
+
+   /*
+    * (non-Javadoc)
+    * @see org.apache.catalina.authenticator.SingleSignOn#associate(java.lang.String, org.apache.catalina.Session)
+    */
+   @Override
+   public void associate(String ssoId, Session session)
+   {
+      super.associate(ssoId, session);
+   }
+   
+   /*
+    * (non-Javadoc)
+    * @see org.apache.catalina.authenticator.SingleSignOn#register(java.lang.String, java.security.Principal, java.lang.String, java.lang.String, java.lang.String)
+    */
+   @Override
+   public void register(String ssoId, Principal principal, String authType, String username, String password)
+   {
+      // TODO Auto-generated method stub
+      super.register(ssoId, principal, authType, username, password);
+   }
+   
+   /*
+    * (non-Javadoc)
+    * @see org.apache.catalina.authenticator.SingleSignOn#update(java.lang.String, java.security.Principal, java.lang.String, java.lang.String, java.lang.String)
+    */
+   @Override
+   public void update(String ssoId, Principal principal, String authType, String username, String password)
+   {
+      super.update(ssoId, principal, authType, username, password);
+   }
+}

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java	2007-10-31 14:18:22 UTC (rev 66611)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java	2007-10-31 14:22:51 UTC (rev 66612)
@@ -58,7 +58,9 @@
    public static ThreadLocal activeWebMetaData = new ThreadLocal();
    /** Maintain the Catalina Request for programmatic web login */
    public static ThreadLocal activeRequest = new ThreadLocal();
-
+   /** Maintain the Catalina Response for programmatic web login */
+   public static ThreadLocal activeResponse = new ThreadLocal();
+   
    /** The web app metadata */
    private WebMetaData metaData;
    /** The name in the session under which the Subject is stored */
@@ -102,8 +104,9 @@
          log.trace("Begin invoke, caller"+caller);
       // Set the active meta data
       activeWebMetaData.set(metaData);
-      //Set the active request
+      //Set the active request and response
       activeRequest.set(request);
+      activeResponse.set(response);
       try
       {
          try
@@ -213,6 +216,7 @@
          activeWebMetaData.set(null);
          userPrincipal.set(null);
          activeRequest.set(null);
+         activeResponse.set(null);
       }
    }
 

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java	2007-10-31 14:18:22 UTC (rev 66611)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java	2007-10-31 14:22:51 UTC (rev 66612)
@@ -20,15 +20,22 @@
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
 package org.jboss.web.tomcat.security.login;
- 
+
 import java.security.Principal;
 import java.security.cert.X509Certificate;
+import java.util.UUID;
 
 import javax.naming.NamingException;
+import javax.servlet.http.Cookie;
 
+import org.apache.catalina.Container;
+import org.apache.catalina.Pipeline;
 import org.apache.catalina.Session;
+import org.apache.catalina.Valve;
 import org.apache.catalina.authenticator.Constants;
 import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.jboss.web.tomcat.security.ExtendedSingleSignOn;
 import org.jboss.web.tomcat.security.SecurityAssociationValve;
 
 //$Id$
@@ -40,12 +47,13 @@
  *  @version $Revision$
  */
 public class WebAuthentication
-{  
+{
    private static final String AUTH_TYPE = "PROGRAMMATIC_WEB_LOGIN";
+
    public WebAuthentication()
-   {  
+   {
    }
-   
+
    /**
     * Login an user via the CLIENT-CERT method
     * @param certs X509 certificates
@@ -55,16 +63,16 @@
    {
       //Get the active request
       Request request = (Request) SecurityAssociationValve.activeRequest.get();
-      if(request == null)
+      if (request == null)
          throw new IllegalStateException("request is null");
       Principal p = request.getContext().getRealm().authenticate(certs);
-      if(p != null)
+      if (p != null)
       {
-         register(request,p, null, null);
+         register(request, p, null, null);
       }
-      return p!= null; 
+      return p != null;
    }
-   
+
    /**
     * Login an user via the BASIC, FORM, DIGEST methods
     * @param username
@@ -72,29 +80,29 @@
     * @return
     * @throws NamingException
     */
-   public boolean login(String username, Object credential) 
-   { 
+   public boolean login(String username, Object credential)
+   {
       //Get the active request
       Request request = (Request) SecurityAssociationValve.activeRequest.get();
-      if(request == null)
+      if (request == null)
          throw new IllegalStateException("request is null");
-      
+
       Principal p = null;
-      if(credential instanceof String)
+      if (credential instanceof String)
       {
-         p = request.getContext().getRealm().authenticate(username, (String)credential); 
-      } 
+         p = request.getContext().getRealm().authenticate(username, (String) credential);
+      }
       else if (credential instanceof byte[])
       {
-         p = request.getContext().getRealm().authenticate(username, (byte[])credential); 
-      } 
-      if(p != null)
+         p = request.getContext().getRealm().authenticate(username, (byte[]) credential);
+      }
+      if (p != null)
       {
-         register(request,p, username, credential);
+         register(request, p, username, credential);
       }
       return p != null;
-   } 
-   
+   }
+
    /**
     * Log the user out
     *
@@ -103,11 +111,11 @@
    {
       //Get the active request
       Request request = (Request) SecurityAssociationValve.activeRequest.get();
-      if(request == null)
+      if (request == null)
          throw new IllegalStateException("request is null");
       unregister(request);
    }
-   
+
    /**
     * Register the principal with the request, session etc just the way AuthenticatorBase does
     * @param request Catalina Request
@@ -118,25 +126,72 @@
    protected void register(Request request, Principal principal, String username, Object password)
    {
       request.setAuthType(AUTH_TYPE);
-      request.setUserPrincipal(principal); 
-      
+      request.setUserPrincipal(principal);
+
       //Cache the authentication principal in the session
       Session session = request.getSessionInternal(false);
-      if(session != null)
+      if (session != null)
       {
          session.setAuthType(AUTH_TYPE);
          session.setPrincipal(principal);
          if (username != null)
-             session.setNote(Constants.SESS_USERNAME_NOTE, username);
+            session.setNote(Constants.SESS_USERNAME_NOTE, username);
          else
-             session.removeNote(Constants.SESS_USERNAME_NOTE);
+            session.removeNote(Constants.SESS_USERNAME_NOTE);
          if (password != null)
-             session.setNote(Constants.SESS_PASSWORD_NOTE, getPasswordAsString(password));
+            session.setNote(Constants.SESS_PASSWORD_NOTE, getPasswordAsString(password));
          else
-             session.removeNote(Constants.SESS_PASSWORD_NOTE);
+            session.removeNote(Constants.SESS_PASSWORD_NOTE);
       }
+
+      // JBAS-4424: Programmatic web authentication with SSO
+      ExtendedSingleSignOn sso = this.getSingleSignOn(request);
+      if (sso == null)
+         return;
+
+      // Only create a new SSO entry if the SSO did not already set a note
+      // for an existing entry (as it would do with subsequent requests
+      // for DIGEST and SSL authenticated contexts)
+      String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+      if (ssoId == null)
+      {
+         // Construct a cookie to be returned to the client
+         ssoId = generateSessionId();
+         Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
+         cookie.setMaxAge(-1);
+         cookie.setPath("/");
+         cookie.setSecure(request.isSecure());
+
+         String ssoDomain = sso.getCookieDomain();
+         if (ssoDomain != null)
+         {
+            cookie.setDomain(ssoDomain);
+         }
+
+         Response response = (Response) SecurityAssociationValve.activeResponse.get();
+         response.addCookie(cookie);
+
+         // Register this principal with our SSO valve
+         sso.register(ssoId, principal, AUTH_TYPE, username, this.getPasswordAsString(password));
+         request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
+
+      }
+      else
+      {
+         // Update the SSO session with the latest authentication data
+         sso.update(ssoId, principal, AUTH_TYPE, username, this.getPasswordAsString(password));
+      }
+
+      // Always associate a session with a new SSO reqistration.
+      // SSO entries are only removed from the SSO registry map when
+      // associated sessions are destroyed; if a new SSO entry is created
+      // above for this request and the user never revisits the context, the
+      // SSO entry will never be cleared if we don't associate the session
+      if (session == null)
+         session = request.getSessionInternal(true);
+      sso.associate(ssoId, session);
    }
-   
+
    /**
     * Log the user out
     * @param request
@@ -144,11 +199,11 @@
    protected void unregister(Request request)
    {
       request.setAuthType(null);
-      request.setUserPrincipal(null); 
-      
+      request.setUserPrincipal(null);
+
       //Cache the authentication principal in the session
       Session session = request.getSessionInternal(false);
-      if(session != null)
+      if (session != null)
       {
          session.setAuthType(null);
          session.setPrincipal(null);
@@ -156,19 +211,70 @@
          session.removeNote(Constants.SESS_PASSWORD_NOTE);
       }
    }
-   
+
    private String getPasswordAsString(Object cred)
    {
       String p = null;
-      
-      if(cred instanceof String)
+
+      if (cred instanceof String)
       {
-         p = (String)cred;
+         p = (String) cred;
       }
-      else if(cred instanceof byte[])
+      else if (cred instanceof byte[])
       {
-         p = new String((byte[])cred);
+         p = new String((byte[]) cred);
       }
       return p;
    }
+
+   /**
+    * <p>
+    * Generate and return a new session identifier for the cookie that identifies an SSO principal.
+    * </p>
+    * 
+    * @return a <code>String</code> representing the generated identifier.
+    */
+   private String generateSessionId()
+   {
+      UUID uid = UUID.randomUUID();
+      String higherBits = Long.toHexString(uid.getMostSignificantBits());
+      String lowerBits = Long.toHexString(uid.getLeastSignificantBits());
+
+      return (higherBits + lowerBits).toUpperCase();
+   }
+   
+   /**
+    * <p>
+    * Obtain a reference to the <code>ExtendedSingleSignOn</code> valve, if one was configured.
+    * </p>
+    * 
+    * @param request    the <code>Request</code> object used to look up the SSO valve.
+    * @return   a reference to the <code>ExtendedSingleSignOn</code> valve, or <code>null</code> if that valve
+    * has not been configured.
+    */
+   private ExtendedSingleSignOn getSingleSignOn(Request request)
+   {
+      ExtendedSingleSignOn sso = null;
+      Container parent = request.getContext().getParent();
+      while ((sso == null) && (parent != null))
+      {
+         if (!(parent instanceof Pipeline))
+         {
+            parent = parent.getParent();
+            continue;
+         }
+         Valve valves[] = ((Pipeline) parent).getValves();
+         for (int i = 0; i < valves.length; i++)
+         {
+            if (valves[i] instanceof ExtendedSingleSignOn)
+            {
+               sso = (ExtendedSingleSignOn) valves[i];
+               break;
+            }
+         }
+         if (sso == null)
+            parent = parent.getParent();
+      }
+      return sso;
+   }
 }

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/ClusteredSingleSignOn.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/ClusteredSingleSignOn.java	2007-10-31 14:18:22 UTC (rev 66611)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/sso/ClusteredSingleSignOn.java	2007-10-31 14:22:51 UTC (rev 66612)
@@ -40,6 +40,7 @@
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
 import org.apache.catalina.session.ManagerBase;
+import org.jboss.web.tomcat.security.ExtendedSingleSignOn;
 import org.jboss.web.tomcat.service.JBossWeb;
 import org.jboss.web.tomcat.service.session.JBossManager;
 
@@ -67,7 +68,7 @@
  * @version $Revision: 57329 $ $Date: 2006-10-02 00:35:46 +0200 (lun., 02 oct. 2006) $
  */
 public class ClusteredSingleSignOn
-   extends org.apache.catalina.authenticator.SingleSignOn
+   extends ExtendedSingleSignOn
    implements LifecycleListener
 {
    /** By default we process expired SSOs no more often than once per minute */
@@ -690,7 +691,7 @@
     * @param ssoId   Single sign on identifier
     * @param session Session to be associated
     */
-   protected void associate(String ssoId, Session session)
+   public void associate(String ssoId, Session session)
    {
       if (getContainer().getLogger().isDebugEnabled())
           getContainer().getLogger().debug("Associate sso id " + ssoId + " with session " + session);
@@ -947,7 +948,7 @@
     * @param username  Username used to authenticate this user
     * @param password  Password used to authenticate this user
     */
-   protected void register(String ssoId, Principal principal, String authType,
+   public void register(String ssoId, Principal principal, String authType,
       String username, String password)
    {
       registerLocal(ssoId, principal, authType, username, password);
@@ -1030,7 +1031,7 @@
     * @param username  the username (if any) used for the authentication
     * @param password  the password (if any) used for the authentication
     */
-   protected void update(String ssoId, Principal principal, String authType,
+   public void update(String ssoId, Principal principal, String authType,
       String username, String password)
    {
       boolean needToBroadcast = updateLocal(ssoId, principal, authType,




More information about the jboss-cvs-commits mailing list