You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/10/06 07:10:32 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector HttpResponseBase.java

craigmcc    00/10/05 22:10:21

  Modified:    catalina/src/share/org/apache/catalina/authenticator
                        AuthenticatorBase.java BasicAuthenticator.java
                        Constants.java DigestAuthenticator.java
                        FormAuthenticator.java SSLAuthenticator.java
               catalina/src/share/org/apache/catalina/connector
                        HttpResponseBase.java
  Added:       catalina/docs singlesignon.html
               catalina/src/share/org/apache/catalina/authenticator
                        SingleSignOn.java
  Log:
  Initial support for "single sign on" across all of the web applications
  associated with a particular virtual host, without requiring users to log
  in to each application individually.  See the included documentation file
  (catalina/docs/singlesignon.html) for more information about configuring
  this facility.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-4.0/catalina/docs/singlesignon.html
  
  Index: singlesignon.html
  ===================================================================
  <html>
  <head>
  <title>Configuring Tomcat 4.0 for Single Sign On Support</title>
  </head>
  <body bgcolor="white">
  
  <div align="center">
  <h1>Configuring Tomcat 4.0 for Single Sign On Support</h1>
  <br>
  <a href="#Introduction">[Introduction]</a>
  <a href="#Requirements">[Requirements]</a>
  <a href="#Security">[Security]</a>
  <br><br>
  </div>
  
  <a name="Introduction"></a>
  <h3>Introduction</h3>
  
  <p>In many large web sites, it is desireable to recognize an authenticated
  user the first time that he or she tries to access a protected area in any
  web application, and then recognize that authenticated user across other web
  applications in the same environment without requiring the user to log in
  again.  Tomcat 4.0 supports that capability if it is configured as described
  in this document.</p>
  
  <a name="Requirements"></a>
  <h3>Configuration Requirements</h3>
  
  <p>To successfully configure Tomcat 4.0 for "single sign on" support, the
  following requirements must be taken into account:</p>
  <ul>
  <li>All clients that intend to utilize "single sign on" support must provide
      support for cookies, which are used to maintain the user identity across
      web applications.</li>
  <li>As implemented in Tomcat 4.0, the scope of "single sign on" support is
      the entire set of web applications registered with a single virtual host.
      </li>
  </ul>
  
  <p>The system administrator must configure the
  <code>$CATALINA_HOME/conf/server.xml</code> file as follows to enable
  "single sign on" support:</p>
  <ul>
  <li>At the <code>&lt;Engine&gt;</code> or <code>&lt;Host&gt;</code> level,
      configure a <code>&lt;Realm&gt;</code> element that defines the database
      of valid users and their corresponding roles.  In the default configuration
      shipped with Tomcat 4.0, this is done at the Engine level.</li>
  <li>You <strong>MUST NOT</strong> configure a <code>&lt;Realm&gt;</code>
      element inside one of the <code>&lt;Context&gt;</code> elements describing
      the web applications associated with this virtual host.</li>
  <li>Nested inside the <code>&lt;Host&gt;</code> element, you must include the
      following element:
      <pre>
          &lt;Valve class="org.apache.catalina.authenticator.SingleSignOn"/&gt;
      </pre></li>
  <li>Each web application that wishes to operate under the "single signon
      support" environment should define appropriate
      <code>&lt;security-constraint&gt;</code> and
      <code>&lt;login-config&gt;</code> elements.  The former elements are used
      to identify portions of the application's URI space that are to require
      user authentication, and the latter element is used if this application
      is the first one accessed by the user that requires the user to log in.
      </li>
  <li>There are no restrictions on different web applications utilizing
      different authentication methods.</li>
  </ul>
  
  <a name="Security"></a>
  <h3>Security Considerations</h3>
  
  <p>Because the "single signon support" implementation utilizes cookies to
  maintain use identity across applications, the same risks of information
  exposure apply here as when cookies are used to maintain session identity
  within a single web application.  If you are concerned that attackers may
  try to impersonate an ongoing session, you should run across a secure
  network connection (such as an SSL connection using the <code>https</code>
  protocol).</p>
  
  <br>
  <div align="center"><hr width="75%"><font size="2">
  $Id: singlesignon.html,v 1.1 2000/10/06 05:10:15 craigmcc Exp $
  </font></div>
  
  </body>
  </html>
  
  
  
  1.2       +276 -3    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java
  
  Index: AuthenticatorBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AuthenticatorBase.java	2000/08/11 22:39:37	1.1
  +++ AuthenticatorBase.java	2000/10/06 05:10:15	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v 1.1 2000/08/11 22:39:37 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 22:39:37 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java,v 1.2 2000/10/06 05:10:15 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/06 05:10:15 $
    *
    * ====================================================================
    *
  @@ -66,8 +66,12 @@
   
   
   import java.io.IOException;
  +import java.security.MessageDigest;
  +import java.security.NoSuchAlgorithmException;
   import java.security.Principal;
  +import java.util.Random;
   import javax.servlet.ServletException;
  +import javax.servlet.http.Cookie;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import javax.servlet.http.HttpSession;
  @@ -82,6 +86,7 @@
   import org.apache.catalina.LifecycleListener;
   import org.apache.catalina.Logger;
   import org.apache.catalina.Manager;
  +import org.apache.catalina.Pipeline;
   import org.apache.catalina.Realm;
   import org.apache.catalina.Request;
   import org.apache.catalina.Response;
  @@ -111,7 +116,7 @@
    * requests.  Requests of any other type will simply be passed through.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 22:39:37 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/06 05:10:15 $
    */
   
   
  @@ -124,6 +129,28 @@
   
   
       /**
  +     * The default message digest algorithm to use if we cannot use
  +     * the requested one.
  +     */
  +    protected static final String DEFAULT_ALGORITHM = "MD5";
  +
  +
  +    /**
  +     * The number of random bytes to include when generating a
  +     * session identifier.
  +     */
  +    protected static final int SESSION_ID_BYTES = 16;
  +
  +
  +    /**
  +     * The message digest algorithm to be used when generating session
  +     * identifiers.  This must be an algorithm supported by the
  +     * <code>java.security.MessageDigest</code> class on your platform.
  +     */
  +    protected String algorithm = DEFAULT_ALGORITHM;
  +
  +
  +    /**
        * Should we cache authenticated Principals if the request is part of
        * an HTTP session?
        */
  @@ -143,6 +170,20 @@
   
   
       /**
  +     * Return the MessageDigest implementation to be used when
  +     * creating session identifiers.
  +     */
  +    protected MessageDigest digest = null;
  +
  +
  +    /**
  +     * A String initialization parameter used to increase the entropy of
  +     * the initialization of our random number generator.
  +     */
  +    protected String entropy = null;
  +
  +
  +    /**
        * Descriptive information about this implementation.
        */
       protected static final String info =
  @@ -156,6 +197,19 @@
   
   
       /**
  +     * A random number generator to use when generating session identifiers.
  +     */
  +    protected Random random = null;
  +
  +
  +    /**
  +     * The Java class name of the random number generator class to be used
  +     * when generating session identifiers.
  +     */
  +    protected String randomClass = "java.security.SecureRandom";
  +
  +
  +    /**
        * The string manager for this package.
        */
       protected static final StringManager sm =
  @@ -163,6 +217,13 @@
   
   
       /**
  +     * The SingleSignOn implementation in our request processing chain,
  +     * if there is one.
  +     */
  +    protected SingleSignOn sso = null;
  +
  +
  +    /**
        * Has this component been started?
        */
       protected boolean started = false;
  @@ -172,6 +233,28 @@
   
   
       /**
  +     * Return the message digest algorithm for this Manager.
  +     */
  +    public String getAlgorithm() {
  +
  +	return (this.algorithm);
  +
  +    }
  +
  +
  +    /**
  +     * Set the message digest algorithm for this Manager.
  +     *
  +     * @param algorithm The new message digest algorithm
  +     */
  +    public void setAlgorithm(String algorithm) {
  +
  +	this.algorithm = algorithm;
  +
  +    }
  +
  +
  +    /**
        * Return the cache authenticated Principals flag.
        */
       public boolean getCache() {
  @@ -243,6 +326,33 @@
   
   
       /**
  +     * Return the entropy increaser value, or compute a semi-useful value
  +     * if this String has not yet been set.
  +     */
  +    public String getEntropy() {
  +
  +	// Calculate a semi-useful value if this has not been set
  +	if (this.entropy == null)
  +	    setEntropy(this.toString());
  +
  +	return (this.entropy);
  +
  +    }
  +
  +
  +    /**
  +     * Set the entropy increaser value.
  +     *
  +     * @param entropy The new entropy increaser value
  +     */
  +    public void setEntropy(String entropy) {
  +
  +	this.entropy = entropy;
  +
  +    }
  +
  +
  +    /**
        * Return descriptive information about this Valve implementation.
        */
       public String getInfo() {
  @@ -252,6 +362,28 @@
       }
   
   
  +    /**
  +     * Return the random number generator class name.
  +     */
  +    public String getRandomClass() {
  +
  +	return (this.randomClass);
  +
  +    }
  +
  +
  +    /**
  +     * Set the random number generator class name.
  +     *
  +     * @param randomClass The new random number generator class name
  +     */
  +    public void setRandomClass(String randomClass) {
  +
  +	this.randomClass = randomClass;
  +
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
   
   
  @@ -520,6 +652,88 @@
   
   
       /**
  +     * Generate and return a new session identifier for the cookie that
  +     * identifies an SSO principal.
  +     */
  +    protected synchronized String generateSessionId() {
  +
  +	// Generate a byte array containing a session identifier
  +	Random random = getRandom();
  +	byte bytes[] = new byte[SESSION_ID_BYTES];
  +	getRandom().nextBytes(bytes);
  +	bytes = getDigest().digest(bytes);
  +
  +	// Render the result as a String of hexadecimal digits
  +	StringBuffer result = new StringBuffer();
  +	for (int i = 0; i < bytes.length; i++) {
  +	    byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
  +	    byte b2 = (byte) (bytes[i] & 0x0f);
  +	    if (b1 < 10)
  +		result.append((char) ('0' + b1));
  +	    else
  +		result.append((char) ('A' + (b1 - 10)));
  +	    if (b2 < 10)
  +		result.append((char) ('0' + b2));
  +	    else
  +		result.append((char) ('0' + (b2 - 10)));
  +	}
  +	return (result.toString());
  +
  +    }
  +
  +
  +    /**
  +     * Return the MessageDigest object to be used for calculating
  +     * session identifiers.  If none has been created yet, initialize
  +     * one the first time this method is called.
  +     */
  +    protected synchronized MessageDigest getDigest() {
  +
  +	if (this.digest == null) {
  +	    try {
  +		this.digest = MessageDigest.getInstance(algorithm);
  +	    } catch (NoSuchAlgorithmException e) {
  +		try {
  +		    this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
  +		} catch (NoSuchAlgorithmException f) {
  +		    this.digest = null;
  +		}
  +	    }
  +	}
  +
  +	return (this.digest);
  +
  +    }
  +
  +
  +    /**
  +     * Return the random number generator instance we should use for
  +     * generating session identifiers.  If there is no such generator
  +     * currently defined, construct and seed a new one.
  +     */
  +    protected synchronized Random getRandom() {
  +
  +	if (this.random == null) {
  +	    try {
  +		Class clazz = Class.forName(randomClass);
  +		this.random = (Random) clazz.newInstance();
  +		long seed = System.currentTimeMillis();
  +		char entropy[] = getEntropy().toCharArray();
  +		for (int i = 0; i < entropy.length; i++) {
  +		    long update = ((byte) entropy[i]) << ((i % 8) * 8);
  +		    seed ^= update;		    
  +		}
  +	    } catch (Exception e) {
  +		this.random = new java.util.Random();
  +	    }
  +	}
  +
  +	return (this.random);
  +
  +    }
  +
  +
  +    /**
        * Return the internal Session that is associated with this HttpRequest,
        * or <code>null</code> if there is no such Session.
        *
  @@ -600,6 +814,37 @@
       }
   
   
  +    /**
  +     * Register an authenticated Principal with our SingleSignOn valve,
  +     * if there is one, and set the appropriate Cookie to be returned.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param response The servlet response we are generating
  +     * @param principal The authenticated Principal to be registered
  +     */
  +    protected void register(Request request, Response response,
  +                            Principal principal) {
  +
  +        if (sso == null)
  +            return;
  +
  +        // Construct a cookie to be returned to the client
  +        HttpServletRequest hreq =
  +            (HttpServletRequest) request.getRequest();
  +        HttpServletResponse hres =
  +            (HttpServletResponse) response.getResponse();
  +        String value = generateSessionId();
  +        Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, value);
  +        cookie.setMaxAge(-1);
  +        cookie.setPath("/");
  +        hres.addCookie(cookie);
  +
  +        // Register this principal with our SSO valve
  +        sso.register(value, principal);
  +
  +    }
  +
  +
       // ------------------------------------------------------ Lifecycle Methods
   
   
  @@ -646,6 +891,32 @@
   	lifecycle.fireLifecycleEvent(START_EVENT, null);
   	started = true;
   
  +        // Look up the SingleSignOn implementation in our request processing
  +        // path, if there is one
  +        Container parent = context.getParent();
  +        while ((sso == null) && (parent != null)) {
  +            if (!(parent instanceof Pipeline)) {
  +                parent = parent.getParent();
  +                continue;
  +            }
  +            Valve valve = ((Pipeline) parent).findValves();
  +            while ((sso == null) && (valve != null)) {
  +                if (valve instanceof SingleSignOn) {
  +                    sso = (SingleSignOn) valve;
  +                    break;
  +                }
  +                valve = valve.getNext();
  +            }
  +            if (sso == null)
  +                parent = parent.getParent();
  +        }
  +        if (debug >= 1) {
  +            if (sso != null)
  +                log("Found SingleSignOn Valve at " + sso);
  +            else
  +                log("No SingleSignOn Valve is present");
  +        }
  +
       }
   
   
  @@ -666,6 +937,8 @@
   		(sm.getString("authenticator.notStarted"));
   	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
   	started = false;
  +
  +        sso = null;
   
       }
   
  
  
  
  1.2       +4 -3      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java
  
  Index: BasicAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- BasicAuthenticator.java	2000/08/11 22:39:37	1.1
  +++ BasicAuthenticator.java	2000/10/06 05:10:16	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java,v 1.1 2000/08/11 22:39:37 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 22:39:37 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java,v 1.2 2000/10/06 05:10:16 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/06 05:10:16 $
    *
    * ====================================================================
    *
  @@ -84,7 +84,7 @@
    * and Digest Access Authentication."
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 22:39:37 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/06 05:10:16 $
    */
   
   public final class BasicAuthenticator
  @@ -173,6 +173,7 @@
   		request.setUserPrincipal(principal);
   		if (cache && (session != null))
   		    session.setPrincipal(principal);
  +                register(request, response, principal);
   		return (true);
   	    }
   	}
  
  
  
  1.2       +5 -2      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Constants.java	2000/08/11 22:39:38	1.1
  +++ Constants.java	2000/10/06 05:10:16	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v 1.1 2000/08/11 22:39:38 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 22:39:38 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/Constants.java,v 1.2 2000/10/06 05:10:16 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/06 05:10:16 $
    *
    * ====================================================================
    *
  @@ -86,6 +86,9 @@
   	"org.apache.catalina.security.REQUEST";
       public static final String FORM_PASSWORD = "j_password";
       public static final String FORM_USERNAME = "j_username";
  +
  +    // Cookie name for single sign on support
  +    public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO";
   
   }
   
  
  
  
  1.2       +4 -3      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java
  
  Index: DigestAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DigestAuthenticator.java	2000/08/11 22:39:38	1.1
  +++ DigestAuthenticator.java	2000/10/06 05:10:17	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java,v 1.1 2000/08/11 22:39:38 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 22:39:38 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java,v 1.2 2000/10/06 05:10:17 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/06 05:10:17 $
    *
    * ====================================================================
    *
  @@ -88,7 +88,7 @@
    * 
    * @author Craig R. McClanahan
    * @author Remy Maucherat
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 22:39:38 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/06 05:10:17 $
    */
   
   public final class DigestAuthenticator
  @@ -247,6 +247,7 @@
   		request.setUserPrincipal(principal);
   		if (cache && (session != null))
   		    session.setPrincipal(principal);
  +                register(request, response, principal);
   		return (true);
   	    }
   	}
  
  
  
  1.3       +5 -4      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java
  
  Index: FormAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FormAuthenticator.java	2000/09/25 21:46:31	1.2
  +++ FormAuthenticator.java	2000/10/06 05:10:17	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v 1.2 2000/09/25 21:46:31 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/09/25 21:46:31 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java,v 1.3 2000/10/06 05:10:17 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/10/06 05:10:17 $
    *
    * ====================================================================
    *
  @@ -88,7 +88,7 @@
    * Authentication, as described in the Servlet API Specification, Version 2.2.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/09/25 21:46:31 $
  + * @version $Revision: 1.3 $ $Date: 2000/10/06 05:10:17 $
    */
   
   public final class FormAuthenticator
  @@ -204,6 +204,7 @@
   	request.setUserPrincipal(principal);
   	if (cache && (session != null))
   	    session.setPrincipal(principal);
  +        register(request, response, principal);
   	if (restoreRequest(request, session))
   	    return (true);		// Perform the original request
   	else {
  
  
  
  1.2       +4 -3      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java
  
  Index: SSLAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SSLAuthenticator.java	2000/09/12 00:10:10	1.1
  +++ SSLAuthenticator.java	2000/10/06 05:10:17	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v 1.1 2000/09/12 00:10:10 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/09/12 00:10:10 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java,v 1.2 2000/10/06 05:10:17 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/06 05:10:17 $
    *
    * ====================================================================
    *
  @@ -86,7 +86,7 @@
    * that utilizes SSL certificates to identify client users.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/09/12 00:10:10 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/06 05:10:17 $
    */
   
   public final class SSLAuthenticator
  @@ -193,6 +193,7 @@
           request.setUserPrincipal(principal);
           if (cache && (session != null))
               session.setPrincipal(principal);
  +        register(request, response, principal);
           return (true);
   
       }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java
  
  Index: SingleSignOn.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java,v 1.1 2000/10/06 05:10:18 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/10/06 05:10:18 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.catalina.authenticator;
  
  
  import java.io.IOException;
  import java.security.Principal;
  import java.util.HashMap;
  import javax.servlet.ServletException;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import org.apache.catalina.Container;
  import org.apache.catalina.HttpRequest;
  import org.apache.catalina.HttpResponse;
  import org.apache.catalina.Logger;
  import org.apache.catalina.Request;
  import org.apache.catalina.Response;
  import org.apache.catalina.valves.ValveBase;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * A <strong>Valve</strong> that supports a "single sign on" user experience,
   * where the security identity of a user who successfully authenticates to one
   * web application is propogated to other web applications in the same
   * security domain.  For successful use, the following requirements must
   * be met:
   * <ul>
   * <li>This Valve must be configured on the Container that represents a
   *     virtual host (typically an implementation of <code>Host</code>).</li>
   * <li>The <code>Realm</code> that contains the shared user and role
   *     information must be configured on the same Container (or a higher
   *     one), and not overridden at the web application level.</li>
   * <li>The web applications themselves must use one of the standard
   *     Authenticators found in the
   *     <code>org.apache.catalina.authenticator</code> package.</li>
   * </ul>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/10/06 05:10:18 $
   */
  
  public class SingleSignOn
      extends ValveBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The cache of authenticated Principals, keyed by the cookie value that
       * is used to select them.
       */
      protected HashMap cache = new HashMap();
  
  
      /**
       * Descriptive information about this Valve implementation.
       */
      protected static String info =
          "org.apache.catalina.authenticator.SingleSignOn";
  
  
      /**
       * The string manager for this package.
       */
      protected final static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ---------------------------------------------------------- Valve Methods
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (info);
  
      }
  
  
      /**
       * Perform single-sign-on support processing for this request.
       *
       * @param request The servlet request we are processing
       * @param response The servlet response we are creating
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if a servlet error occurs
       */
      public void invoke(Request request, Response response)
          throws IOException, ServletException {
  
          // If this is not an HTTP request and response, just pass them on
          if (!(request instanceof HttpRequest) ||
              !(response instanceof HttpResponse)) {
              invokeNext(request, response);
              return;
          }
  
          // Has a valid user already been authenticated?
          HttpServletRequest hreq =
              (HttpServletRequest) request.getRequest();
          if (hreq.getUserPrincipal() != null) {
              invokeNext(request, response);
              return;
          }
  
          // Check for the single sign on cookie
          log("Checking for SSO cookie");
          Cookie cookie = null;
          Cookie cookies[] = hreq.getCookies();
          if (cookies == null)
              cookies = new Cookie[0];
          for (int i = 0; i < cookies.length; i++) {
              if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) {
                  cookie = cookies[i];
                  break;
              }
          }
          if (cookie == null) {
              invokeNext(request, response);
              return;
          }
  
          // Look up the cached Principal associated with this cookie value
          log("Checking for cached principal");
          Principal principal = lookup(cookie.getValue());
          if (principal != null) {
              log("Found cached principal '" + principal.getName() + "'");
              ((HttpRequest) request).setUserPrincipal(principal);
          }
  
          // Invoke the next Valve in our pipeline
          invokeNext(request, response);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Deregister the specified cookie value for the single sign on cookie.
       *
       * @param cookie Cookie value for the single sign on cookie to deregister
       */
      public void deregister(String cookie) {
  
          log("Deregistering cookie value '" + cookie + "'");
  
          synchronized (cache) {
              cache.remove(cookie);
          }
  
      }
  
  
      /**
       * Register the specified Principal as being associated with the specified
       * value for the single sign on cookie.
       *
       * @param cookie Cookie value for the single sign on cookie
       * @param principal Associated user principal that is identified
       */
      public void register(String cookie, Principal principal) {
  
          log("Registering cookie value '" + cookie + "' for user '" +
              principal.getName() + "'");
  
          synchronized (cache) {
              cache.put(cookie, principal);
          }
  
      }
  
  
      /**
       * Return a String rendering of this object.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer("SingleSignOn[");
          sb.append(container.getName());
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       */
      protected void log(String message) {
  
  	Logger logger = container.getLogger();
  	if (logger != null)
  	    logger.log(this.toString() + ": " + message);
  	else
  	    System.out.println(this.toString() + ": " + message);
  
      }
  
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       * @param throwable Associated exception
       */
      protected void log(String message, Throwable throwable) {
  
  	Logger logger = container.getLogger();
  	if (logger != null)
  	    logger.log(this.toString() + ": " + message, throwable);
  	else {
  	    System.out.println(this.toString() + ": " + message);
  	    throwable.printStackTrace(System.out);
  	}
  
      }
  
  
      /**
       * Look up and return the cached Principal associated with this cookie
       * value, if there is one; otherwise return <code>null</code>.
       *
       * @param cookie Cookie value to look up
       */
      protected Principal lookup(String cookie) {
  
          // FIXME - No timeout checking on cached Principals
          synchronized (cache) {
              return ((Principal) cache.get(cookie));
          }
  
      }
  
  
  }
  
  
  
  1.11      +10 -7     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpResponseBase.java
  
  Index: HttpResponseBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpResponseBase.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- HttpResponseBase.java	2000/10/03 21:30:31	1.10
  +++ HttpResponseBase.java	2000/10/06 05:10:20	1.11
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpResponseBase.java,v 1.10 2000/10/03 21:30:31 craigmcc Exp $
  - * $Revision: 1.10 $
  - * $Date: 2000/10/03 21:30:31 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpResponseBase.java,v 1.11 2000/10/06 05:10:20 craigmcc Exp $
  + * $Revision: 1.11 $
  + * $Date: 2000/10/06 05:10:20 $
    *
    * ====================================================================
    *
  @@ -96,7 +96,7 @@
    * methods need to be implemented.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.10 $ $Date: 2000/10/03 21:30:31 $
  + * @version $Revision: 1.11 $ $Date: 2000/10/06 05:10:20 $
    */
   
   public class HttpResponseBase
  @@ -463,17 +463,17 @@
   	    outputWriter.print(message);
   	}
   	outputWriter.print("\r\n");
  -//	log(request.getRequest().getProtocol() + " " + status + " " + message);
  +        //	log(request.getRequest().getProtocol() + " " + status + " " + message);
   
   	// Send the content-length and content-type headers (if any)
   	if (getContentType() != null) {
   	    outputWriter.print("Content-Type: " + getContentType() + "\r\n");
  -//	    log(" Content-Type: " + getContentType());
  +            //	    log(" Content-Type: " + getContentType());
   	}
   	if (getContentLength() >= 0) {
   	    outputWriter.print("Content-Length: " + getContentLength() +
   			       "\r\n");
  -//	    log("  Content-Length: " + getContentLength());
  +            //	    log("  Content-Length: " + getContentLength());
   	}
   
   	// Send all specified headers (if any)
  @@ -489,6 +489,7 @@
   		    outputWriter.print(": ");
   		    outputWriter.print(value);
   		    outputWriter.print("\r\n");
  +                    //                    log(" " + name + ": " + value);
   		}
   	    }
   	}
  @@ -523,6 +524,8 @@
   		outputWriter.print(": ");
   		outputWriter.print(CookieTools.getCookieHeaderValue(cookie));
   		outputWriter.print("\r\n");
  +                //                log(" " + CookieTools.getCookieHeaderName(cookie) + ": " +
  +                //                    CookieTools.getCookieHeaderValue(cookie));
   	    }
   	}