tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From craig...@locus.apache.org
Subject cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator AuthenticatorBase.java BasicAuthenticator.java Constants.java DigestAuthenticator.java FormAuthenticator.java LocalStrings.properties SavedRequest.java package.html
Date Wed, 26 Jul 2000 22:08:21 GMT
craigmcc    00/07/26 15:08:20

  Added:       proposals/catalina/src/share/org/apache/tomcat/authenticator
                        AuthenticatorBase.java BasicAuthenticator.java
                        Constants.java DigestAuthenticator.java
                        FormAuthenticator.java LocalStrings.properties
                        SavedRequest.java package.html
  Log:
  Migrate Authenticator implementations to their new package home.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/AuthenticatorBase.java
  
  Index: AuthenticatorBase.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/AuthenticatorBase.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  import java.io.IOException;
  import java.security.Principal;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import org.apache.tomcat.Authenticator;
  import org.apache.tomcat.Container;
  import org.apache.tomcat.Context;
  import org.apache.tomcat.HttpRequest;
  import org.apache.tomcat.HttpResponse;
  import org.apache.tomcat.Lifecycle;
  import org.apache.tomcat.LifecycleEvent;
  import org.apache.tomcat.LifecycleException;
  import org.apache.tomcat.LifecycleListener;
  import org.apache.tomcat.Logger;
  import org.apache.tomcat.Manager;
  import org.apache.tomcat.Realm;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Response;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.Valve;
  import org.apache.tomcat.deploy.LoginConfig;
  import org.apache.tomcat.deploy.SecurityConstraint;
  import org.apache.tomcat.util.LifecycleSupport;
  import org.apache.tomcat.util.StringManager;
  import org.apache.tomcat.valves.ValveBase;
  
  
  /**
   * Basic implementation of the <b>Valve</b> interface that enforces the
   * <code>&lt;security-constraint&gt;</code> elements in the web application
   * deployment descriptor.  This functionality is implemented as a Valve
   * so that it can be ommitted in environments that do not require these
   * features.  Individual implementations of each supported authentication
   * method can subclass this base class as required.
   * <p>
   * <b>USAGE CONSTRAINT</b>:  When this class is utilized, the Context to
   * which it is attached (or a parent Container in a hierarchy) must have an
   * associated Realm that can be used for authenticating users and enumerating
   * the roles to which they have been assigned.
   * <p>
   * <b>USAGE CONSTRAINT</b>:  This Valve is only useful when processing HTTP
   * requests.  Requests of any other type will simply be passed through.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/07/26 22:08:20 $
   */
  
  
  public abstract class AuthenticatorBase
      extends ValveBase
      implements Authenticator, Lifecycle {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Should we cache authenticated Principals if the request is part of
       * an HTTP session?
       */
      protected boolean cache = true;
  
  
      /**
       * The Context to which this Valve is attached.
       */
      protected Context context = null;
  
  
      /**
       * The debugging detail level for this component.
       */
      protected int debug = 0;
  
  
      /**
       * Descriptive information about this implementation.
       */
      protected static final String info =
  	"org.apache.tomcat.authenticator.AuthenticatorBase/1.0";
  
  
      /**
       * The lifecycle event support for this component.
       */
      protected LifecycleSupport lifecycle = new LifecycleSupport(this);
  
  
      /**
       * The string manager for this package.
       */
      protected static final StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      /**
       * Has this component been started?
       */
      protected boolean started = false;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the cache authenticated Principals flag.
       */
      public boolean getCache() {
  
  	return (this.cache);
  
      }
  
  
      /**
       * Set the cache authenticated Principals flag.
       *
       * @param cache The new cache flag
       */
      public void setCache(boolean cache) {
  
  	this.cache = cache;
  
      }
  
  
      /**
       * Return the Container to which this Valve is attached.
       */
      public Container getContainer() {
  
  	return (this.context);
  
      }
  
  
      /**
       * Set the Container to which this Valve is attached.
       *
       * @param container The container to which we are attached
       */
      public void setContainer(Container container) {
  
  	if (!(container instanceof Context))
  	    throw new IllegalArgumentException
  		(sm.getString("authenticator.notContext"));
  
  	super.setContainer(container);
  	this.context = (Context) container;
  
      }
  
  
      /**
       * Return the debugging detail level for this component.
       */
      public int getDebug() {
  
          return (this.debug);
  
      }
  
  
      /**
       * Set the debugging detail level for this component.
       *
       * @param debug The new debugging detail level
       */
      public void setDebug(int debug) {
  
          this.debug = debug;
  
      }
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Enforce the security restrictions in the web application deployment
       * descriptor of our associated Context.
       *
       * @param request Request to be processed
       * @param response Response to be processed
       *
       * @exception IOException if an input/output error occurs
       * @exception ServletException if thrown by a processing element
       */
      public void invoke(Request request, Response response)
  	throws IOException, ServletException {
  
  	// If this is not an HTTP request, do nothing
  	if (!(request instanceof HttpRequest) ||
              !(response instanceof HttpResponse)) {
  	    invokeNext(request, response);
  	    return;
  	}
  	if (!(request.getRequest() instanceof HttpServletRequest) ||
  	    !(response.getResponse() instanceof HttpServletResponse)) {
  	    invokeNext(request, response);
  	    return;
  	}
  	HttpRequest hrequest = (HttpRequest) request;
  	HttpResponse hresponse = (HttpResponse) response;
  	if (debug >= 1)
  	    log("Security checking request " +
  		((HttpServletRequest) request.getRequest()).getMethod() + " " +
  		((HttpServletRequest) request.getRequest()).getRequestURI());
  	LoginConfig config = context.getLoginConfig();
  
  	// Special handling for form-based logins to deal with the case
  	// where the login form (and therefore the "j_security_check" URI
  	// to which it submits) might be outside the secured area
  	String contextPath = context.getPath();
  	String requestURI =
  	    ((HttpServletRequest) request.getRequest()).getRequestURI();
  	if (requestURI.startsWith(contextPath) &&
  	    requestURI.endsWith(Constants.FORM_ACTION)) {
  	    if (!authenticate(hrequest, hresponse, config)) {
  		if (debug >= 1)
  		    log(" Failed authenticate() test");
  		return;
  	    }
  	}
  
  	// Is this request URI subject to a security constraint?
  	SecurityConstraint constraint = findConstraint(hrequest);
  	if ((constraint == null) /* &&
  	    (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) {
  	    if (debug >= 1)
  	        log(" Not subject to any constraint");
  	    invokeNext(request, response);
  	    return;
  	}
  	if ((debug >= 1) && (constraint != null))
  	    log(" Subject to constraint " + constraint);
  
  	// Enforce any user data constraint for this security constraint
  	if (!checkUserData(hrequest, hresponse, constraint)) {
  	    if (debug >= 1)
  	        log(" Failed checkUserData() test");
  	    return;
  	}
  
  	// Authenticate based upon the specified login configuration
  	if (!authenticate(hrequest, hresponse, config)) {
  	    if (debug >= 1)
  	        log(" Failed authenticate() test");
  	    return;
  	}
  
  	// Perform access control based on the specified role(s)
  	if (!accessControl(hrequest, hresponse, constraint)) {
  	    if (debug >= 1)
  	        log(" Failed accessControl() test");
  	    return;
  	}
  
  	// Any and all specified constraints have been satisfied
  	if (debug >= 1)
  	    log(" Successfully passed all security constraints");
  	invokeNext(request, response);
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Perform access control based on the specified authorization constraint.
       * Return <code>true</code> if this constraint is satisfied and processing
       * should continue, or <code>false</code> otherwise.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param constraint Security constraint we are enforcing
       *
       * @exception IOException if an input/output error occurs
       */
      protected boolean accessControl(HttpRequest request,
  				    HttpResponse response,
  				    SecurityConstraint constraint)
  	throws IOException {
  
  	if (constraint == null)
  	    return (true);
  
  	// Specifically allow access to the form login and form error pages
  	LoginConfig config = context.getLoginConfig();
  	if ((config != null) &&
  	    (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
  	    String requestURI =
  		((HttpServletRequest) request.getRequest()).getRequestURI();
  	    String loginPage = context.getPath() + config.getLoginPage();
  	    if (loginPage.equals(requestURI)) {
  		if (debug >= 1)
  		    log(" Allow access to login page " + loginPage);
  		return (true);
  	    }
  	    String errorPage = context.getPath() + config.getErrorPage();
  	    if (errorPage.equals(requestURI)) {
  		if (debug >= 1)
  		    log(" Allow access to error page " + errorPage);
  		return (true);
  	    }
  	    if (requestURI.endsWith(Constants.FORM_ACTION)) {
  		if (debug >= 1)
  		    log(" Allow access to username/password submission");
  		return (true);
  	    }
  	}
  
  	// Which user principal have we already authenticated?
  	Principal principal =
  	    ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  	if (principal == null) {
  	    ((HttpServletResponse) response.getResponse()).sendError
  		(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
  		 sm.getString("authenticator.notAuthenticated"));
  	    return (false);
  	}
  
  	// Check each role included in this constraint
  	Realm realm = context.getRealm();
  	String roles[] = constraint.findAuthRoles();
  	if (roles == null)
  	    roles = new String[0];
  	if (roles.length == 0)
  	    return (true);	// Authenticated user is sufficient
  	for (int i = 0; i < roles.length; i++) {
  	    if (realm.hasRole(principal, roles[i]))
  		return (true);
  	}
  
  	// Return a "Forbidden" message denying access to this resource
  	((HttpServletResponse) response.getResponse()).sendError
  	    (HttpServletResponse.SC_FORBIDDEN,
  	     sm.getString("authenticator.forbidden"));
  	return (false);
  
      }
  
  
      /**
       * Authenticate the user making this request, based on the specified
       * login configuration.  Return <code>true</code> if any specified
       * constraint has been satisfied, or <code>false</code> if we have
       * created a response challenge already.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param login Login configuration describing how authentication
       *              should be performed
       *
       * @exception IOException if an input/output error occurs
       */
      protected abstract boolean authenticate(HttpRequest request,
  					    HttpResponse response,
  					    LoginConfig config)
  	throws IOException;
  
  
      /**
       * Enforce any user data constraint required by the security constraint
       * guarding this request URI.  Return <code>true</code> if this constraint
       * was not violated and processing should continue, or <code>false</code>
       * if we have created a response already.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param constraint Security constraint being checked
       *
       * @exception IOException if an input/output error occurs
       */
      protected boolean checkUserData(HttpRequest request,
  				    HttpResponse response,
  				    SecurityConstraint constraint)
  	throws IOException {
  
  	// Is there a relevant user data constraint?
  	if (constraint == null)
  	    return (true);
  	String userConstraint = constraint.getUserConstraint();
  	if (userConstraint == null)
  	    return (true);
  	if (userConstraint.equals(Constants.NONE_TRANSPORT))
  	    return (true);
  
  	// Validate the request against the user data constraint
  	if (!request.getRequest().isSecure()) {
  	    ((HttpServletResponse) response.getResponse()).sendError
  		(HttpServletResponse.SC_BAD_REQUEST,
  		 sm.getString("authenticator.userDataConstraint"));
  	    return (false);
  	}
  	return (true);
  
      }
  
  
      /**
       * Return the SecurityConstraint configured to guard the request URI for
       * this request, or <code>null</code> if there is no such constraint.
       * <b>FIXME - Need to do length-first matching.</b>
       *
       * @param request Request we are processing
       */
      protected SecurityConstraint findConstraint(HttpRequest request) {
  
  	// Are there any defined security constraints?
  	SecurityConstraint constraints[] = context.findConstraints();
  	if ((constraints == null) || (constraints.length == 0)) {
  	    if (debug >= 2)
  		log("  No applicable constraints defined");
  	    return (null);
  	}
  
  	// Check each defined security constraint
  	HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
  	String uri = hreq.getRequestURI();
  	String contextPath = hreq.getContextPath();
  	if (contextPath.length() > 0)
  	    uri = uri.substring(contextPath.length());
  	String method = hreq.getMethod();
  	for (int i = 0; i < constraints.length; i++) {
  	    if (debug >= 2)
  		log("  Checking constraint '" + constraints[i] +
  		    "' against " + method + " " + uri + " --> " +
  		    constraints[i].included(uri, method));
  	    if (constraints[i].included(uri, method))
  		return (constraints[i]);
  	}
  
  	// No applicable security constraint was found
  	if (debug >= 2)
  	    log("  No applicable constraint located");
  	return (null);
  
      }
  
  
      /**
       * Return the internal Session that is associated with this HttpRequest,
       * or <code>null</code> if there is no such Session.
       *
       * @param request The HttpRequest we are processing
       */
      protected Session getSession(HttpRequest request) {
  
  	return (getSession(request, false));
  
      }
  
  
      /**
       * Return the internal Session that is associated with this HttpRequest,
       * possibly creating a new one if necessary, or <code>null</code> if
       * there is no such session and we did not create one.
       *
       * @param request The HttpRequest we are processing
       * @param create Should we create a session if needed?
       */
      protected Session getSession(HttpRequest request, boolean create) {
  
  	HttpServletRequest hreq =
  	    (HttpServletRequest) request.getRequest();
  	HttpSession hses = hreq.getSession(create);
  	if (hses == null)
  	    return (null);
  	Manager manager = context.getManager();
  	if (manager == null)
  	    return (null);
  	else {
  	    try {
  		return (manager.findSession(hses.getId()));
  	    } catch (IOException e) {
  		return (null);
  	    }
  	}
  
      }
  
  
      /**
       * 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 = context.getLogger();
  	if (logger != null)
  	    logger.log("Authenticator[" + context.getPath() + "]: " +
  		       message);
  	else
  	    System.out.println("Authenticator[" + context.getPath() +
  			       "]: " + 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 = context.getLogger();
  	if (logger != null)
  	    logger.log("Authenticator[" + context.getPath() + "]: " +
  		       message, throwable);
  	else {
  	    System.out.println("Authenticator[" + context.getPath() +
                                 "]: " + message);
  	    throwable.printStackTrace(System.out);
  	}
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
  
  	lifecycle.addLifecycleListener(listener);
  
      }
  
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removeLifecycleListener(LifecycleListener listener) {
  
  	lifecycle.removeLifecycleListener(listener);
  
      }
  
  
      /**
       * Prepare for the beginning of active use of the public methods of this
       * component.  This method should be called after <code>configure()</code>,
       * and before any of the public methods of the component are utilized.
       *
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception LifecycleException if this component detects a fatal error
       *  that prevents this component from being used
       */
      public void start() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (started)
  	    throw new LifecycleException
  		(sm.getString("authenticator.alreadyStarted"));
  	lifecycle.fireLifecycleEvent(START_EVENT, null);
  	started = true;
  
      }
  
  
      /**
       * Gracefully terminate the active use of the public methods of this
       * component.  This method should be the last one called on a given
       * instance of this component.
       *
       * @exception IllegalStateException if this component has not been started
       * @exception LifecycleException if this component detects a fatal error
       *  that needs to be reported
       */
      public void stop() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (!started)
  	    throw new LifecycleException
  		(sm.getString("authenticator.notStarted"));
  	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  	started = false;
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/BasicAuthenticator.java
  
  Index: BasicAuthenticator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/BasicAuthenticator.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  import java.io.IOException;
  import java.security.Principal;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import org.apache.tomcat.HttpRequest;
  import org.apache.tomcat.HttpResponse;
  import org.apache.tomcat.Realm;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.deploy.LoginConfig;
  import org.apache.tomcat.util.Base64;
  
  
  
  /**
   * An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP BASIC
   * Authentication, as outlined in RFC 2617:  "HTTP Authentication: Basic
   * and Digest Access Authentication."
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/07/26 22:08:20 $
   */
  
  public final class BasicAuthenticator
      extends AuthenticatorBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The Base64 helper object for this class.
       */
      private static final Base64 base64Helper = new Base64();
  
  
      /**
       * Descriptive information about this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.authenticator.BasicAuthenticator/1.0";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Authenticate the user making this request, based on the specified
       * login configuration.  Return <code>true</code> if any specified
       * constraint has been satisfied, or <code>false</code> if we have
       * created a response challenge already.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param login Login configuration describing how authentication
       *              should be performed
       *
       * @exception IOException if an input/output error occurs
       */
      public boolean authenticate(HttpRequest request,
  				HttpResponse response,
  				LoginConfig config)
  	throws IOException {
  
  	// Have we already authenticated someone?
  	Principal principal =
  	    ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  	if (principal != null)
  	    return (true);
  
  	// Have we got a cached authenticated Principal?
  	Session session = null;
  	if (cache)
  	    session = getSession(request);
  	if (session != null) {
  	    principal = session.getPrincipal();
  	    if (principal != null) {
  	        request.setAuthType(Constants.BASIC_METHOD);
  		request.setUserPrincipal(principal);
  		return (true);
  	    }
  	}
  
  	// Validate any credentials already included with this request
  	HttpServletRequest hreq =
  	    (HttpServletRequest) request.getRequest();
  	HttpServletResponse hres =
  	    (HttpServletResponse) response.getResponse();
  	String authorization = request.getAuthorization();
  	if (authorization != null) {
  	    principal = findPrincipal(authorization, context.getRealm());
  	    if (principal != null) {
  	        request.setAuthType(Constants.BASIC_METHOD);
  		request.setUserPrincipal(principal);
  		if (cache && (session != null))
  		    session.setPrincipal(principal);
  		return (true);
  	    }
  	}
  
  	// Send an "unauthorized" response and an appropriate challenge
  	String realmName = config.getRealmName();
  	if (realmName == null)
  	    realmName = hreq.getServerName() + ":" + hreq.getServerPort();
  	hres.setHeader("WWW-Authenticate", 
                         "Basic realm=\"" + realmName + "\"");
          hres.setContentLength(0);
  	hres.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  	hres.flushBuffer();
  	return (false);
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Parse the specified authorization credentials, and return the
       * associated Principal that these credentials authenticate (if any)
       * from the specified Realm.  If there is no such Principal, return
       * <code>null</code>.
       *
       * @param authorization Authorization credentials from this request
       * @param realm Realm used to authenticate Principals
       */
      private static Principal findPrincipal(String authorization, Realm realm) {
  
  	// Validate the authorization credentials format
  	if (authorization == null)
  	    return (null);
  	if (!authorization.startsWith("Basic "))
  	    return (null);
  	authorization = authorization.substring(6).trim();
  
  	// Decode and parse the authorization credentials
  	String unencoded =
  	  new String(base64Helper.decode(authorization.getBytes()));
  	int colon = unencoded.indexOf(':');
  	if (colon < 0)
  	    return (null);
  	String username = unencoded.substring(0, colon).trim();
  	String password = unencoded.substring(colon + 1).trim();
  
  	// Validate these credentials in our associated realm
  	return (realm.authenticate(username, password));
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/Constants.java
  
  Index: Constants.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/Constants.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  public class Constants {
  
      public static final String Package = "org.apache.tomcat.authenticator";
  
      // Authentication methods for login configuration
      public static final String BASIC_METHOD = "BASIC";
      public static final String CERT_METHOD = "CLIENT-CERT";
      public static final String DIGEST_METHOD = "DIGEST";
      public static final String FORM_METHOD = "FORM";
  
      // User data constraints for transport guarantee
      public static final String NONE_TRANSPORT = "NONE";
      public static final String INTEGRAL_TRANSPORT = "INTEGRAL";
      public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL";
  
      // Form based authentication constants
      public static final String FORM_ACTION = "/j_security_check";
      public static final String FORM_KEY = "org.apache.tomcat.security.REQUEST";
      public static final String FORM_PASSWORD = "j_password";
      public static final String FORM_USERNAME = "j_username";
  
  }
  
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/DigestAuthenticator.java
  
  Index: DigestAuthenticator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/DigestAuthenticator.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  import java.io.IOException;
  import java.security.Principal;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Hashtable;
  import java.util.StringTokenizer;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import org.apache.tomcat.HttpRequest;
  import org.apache.tomcat.HttpResponse;
  import org.apache.tomcat.Realm;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.deploy.LoginConfig;
  import org.apache.tomcat.util.MD5Encoder;
  
  
  
  /**
   * An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP DIGEST
   * Authentication (see RFC 2069).
   * 
   * @author Craig R. McClanahan
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2000/07/26 22:08:20 $
   */
  
  public final class DigestAuthenticator
      extends AuthenticatorBase {
  
  
      // -------------------------------------------------------------- Constants
  
  
      /**
       * Indicates that no once tokens are used only once.
       */
      private static final int USE_ONCE = 1;
  
  
      /**
       * Indicates that no once tokens are used only once.
       */
      private static final int USE_NEVER_EXPIRES = Integer.MAX_VALUE;
  
  
      /**
       * Indicates that no once tokens are used only once.
       */
      private static final int TIMEOUT_INFINITE = Integer.MAX_VALUE;
  
  
      /**
       * The MD5 helper object for this class.
       */
      private static final MD5Encoder md5Encoder = new MD5Encoder();
  
  
      /**
       * Descriptive information about this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.authenticator.DigestAuthenticator/1.0";
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public DigestAuthenticator() {
          super();
          try {
              if (md5Helper == null)
                  md5Helper = MessageDigest.getInstance("MD5");
          } catch (NoSuchAlgorithmException e) {
              e.printStackTrace();
              throw new IllegalStateException();
          }
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * MD5 message digest provider.
       */
      private static MessageDigest md5Helper;
  
  
      /**
       * No once hashtable.
       */
      private Hashtable nOnceTokens = new Hashtable();
  
  
      /**
       * No once expiration (in millisecond). A shorter amount would mean a 
       * better security level (since the token is generated more often), but at
       * the expense of a bigger server overhead.
       */
      private long nOnceTimeout = TIMEOUT_INFINITE;
  
  
      /**
       * No once expiration after a specified number of uses. A lower number
       * would produce more overhead, since a token would have to be generated
       * more often, but would be more secure.
       */
      private int nOnceUses = USE_ONCE;
  
  
      /**
       * Private key.
       */
      private String key = "Catalina";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Authenticate the user making this request, based on the specified
       * login configuration.  Return <code>true</code> if any specified
       * constraint has been satisfied, or <code>false</code> if we have
       * created a response challenge already.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param login Login configuration describing how authentication
       *              should be performed
       *
       * @exception IOException if an input/output error occurs
       */
      public boolean authenticate(HttpRequest request,
  				HttpResponse response,
  				LoginConfig config)
  	throws IOException {
  
  	// Have we already authenticated someone?
  	Principal principal =
  	    ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  	if (principal != null)
  	    return (true);
  
  	// Have we got a cached authenticated Principal?
  	Session session = null;
  	if (cache)
  	    session = getSession(request);
  	if (session != null) {
  	    principal = session.getPrincipal();
  	    if (principal != null) {
  	        request.setAuthType(Constants.DIGEST_METHOD);
  		request.setUserPrincipal(principal);
  		return (true);
  	    }
  	}
  
  	// Validate any credentials already included with this request
  	HttpServletRequest hreq =
  	    (HttpServletRequest) request.getRequest();
  	HttpServletResponse hres =
  	    (HttpServletResponse) response.getResponse();
  	String authorization = request.getAuthorization();
  	if (authorization != null) {
  	    principal = findPrincipal(hreq, authorization, context.getRealm());
  	    if (principal != null) {
  	        request.setAuthType(Constants.DIGEST_METHOD);
  		request.setUserPrincipal(principal);
  		if (cache && (session != null))
  		    session.setPrincipal(principal);
  		return (true);
  	    }
  	}
  
  	// Send an "unauthorized" response and an appropriate challenge
          
          // Next, generate a nOnce token (that is a token which is supposed
          // to be unique).
          String nOnce = generateNOnce(hreq);
          
  	setAuthenticateHeader(hreq, hres, config, nOnce);
  	hres.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  	hres.flushBuffer();
  	return (false);
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Parse the specified authorization credentials, and return the
       * associated Principal that these credentials authenticate (if any)
       * from the specified Realm.  If there is no such Principal, return
       * <code>null</code>.
       *
       * @param request HTTP servlet request
       * @param authorization Authorization credentials from this request
       * @param login Login configuration describing how authentication
       *              should be performed
       * @param realm Realm used to authenticate Principals
       */
      private static Principal findPrincipal(HttpServletRequest request, 
                                             String authorization, Realm realm) {
  
          //System.out.println("Authorization token : " + authorization);
  	// Validate the authorization credentials format
  	if (authorization == null)
  	    return (null);
  	if (!authorization.startsWith("Digest "))
  	    return (null);
  	authorization = authorization.substring(7).trim();
          
          
          StringTokenizer commaTokenizer = 
              new StringTokenizer(authorization, ",");
          
          String userName = null;
          String realmName = null;
          String nOnce = null;
          String nc = null;
          String cnonce = null;
          String qop = null;
          String uri = null;
          String response = null;
          String opaque = null;
          String method = request.getMethod();
          
          while (commaTokenizer.hasMoreTokens()) {
              String currentToken = commaTokenizer.nextToken();
              int equalSign = currentToken.indexOf('=');
              if (equalSign < 0)
                  return null;
              String currentTokenName = 
                  currentToken.substring(0, equalSign).trim();
              String currentTokenValue = 
                  currentToken.substring(equalSign + 1).trim();
              if ("username".equals(currentTokenName))
                  userName = removeQuotes(currentTokenValue);
              if ("realm".equals(currentTokenName))
                  realmName = removeQuotes(currentTokenValue);
              if ("nonce".equals(currentTokenName))
                  nOnce = removeQuotes(currentTokenValue);
              if ("nc".equals(currentTokenName))
                  nc = currentTokenValue;
              if ("cnonce".equals(currentTokenName))
                  cnonce = removeQuotes(currentTokenValue);
              if ("qop".equals(currentTokenName))
                  qop = removeQuotes(currentTokenValue);
              if ("uri".equals(currentTokenName))
                  uri = removeQuotes(currentTokenValue);
              if ("response".equals(currentTokenName))
                  response = removeQuotes(currentTokenValue);
          }
          
          if ( (userName == null) || (realmName == null) || (nOnce == null)
               || (uri == null) || (response == null) )
              return null;
          
          // Second MD5 digest used to calculate the digest : 
          // MD5(Method + ":" + uri)
          String a2 = method + ":" + uri;
          //System.out.println("A2:" + a2);
          
          String md5a2 = md5Encoder.encode(md5Helper.digest(a2.getBytes()));
          
          return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop,
                                     realmName, md5a2));
          
      }
  
  
      /**
       * Removes the quotes on a string.
       */
      private static String removeQuotes(String quotedString) {
          if (quotedString.length() > 2) {
              return quotedString.substring(1, quotedString.length() - 1);
          } else {
              return new String();
          }
      }
  
  
      /**
       * Generate a unique token. The token is generated according to the 
       * following pattern. NOnceToken = Base64 ( MD5 ( client-IP ":" 
       * time-stamp ":" private-key ) ).
       * 
       * @param request HTTP Servlet request
       */
      private String generateNOnce(HttpServletRequest request) {
          long currentTime = System.currentTimeMillis();
          
          String nOnceValue = request.getRemoteAddr() + ":" + 
              currentTime + ":" + key;
          
          byte[] buffer = md5Helper.digest(nOnceValue.getBytes());
          nOnceValue = md5Encoder.encode(buffer);
          
          // Updating the value in the no once hashtable
          nOnceTokens.put(nOnceValue, new Long(currentTime + nOnceTimeout));
          
          return nOnceValue;
      }
  
  
      /**
       * Generates the WWW-Authenticate header.
       * <p>
       * The header MUST follow this template :
       * <pre>
       *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
       *                            digest-challenge
       * 
       *      digest-challenge    = 1#( realm | [ domain ] | nOnce |
       *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
       * 
       *      realm               = "realm" "=" realm-value
       *      realm-value         = quoted-string
       *      domain              = "domain" "=" <"> 1#URI <">
       *      nonce               = "nonce" "=" nonce-value
       *      nonce-value         = quoted-string
       *      opaque              = "opaque" "=" quoted-string
       *      stale               = "stale" "=" ( "true" | "false" )
       *      algorithm           = "algorithm" "=" ( "MD5" | token )
       * </pre>
       * 
       * @param request HTTP Servlet request
       * @param resonse HTTP Servlet response
       * @param login Login configuration describing how authentication
       *              should be performed
       * @param nOnce nonce token
       */
      private void setAuthenticateHeader(HttpServletRequest request,
                                         HttpServletResponse response,
                                         LoginConfig config,
                                         String nOnce) {
          
          // Get the realm name
  	String realmName = config.getRealmName();
  	if (realmName == null)
  	    realmName = request.getServerName() + ":" 
                  + request.getServerPort();
          
          byte[] buffer = md5Helper.digest(nOnce.getBytes());
          
          String authenticateHeader = "Digest realm=\"" + realmName + "\", "
              +  "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\"" 
              + md5Encoder.encode(buffer) + "\"";
          // System.out.println("Authenticate header value : " 
          //                   + authenticateHeader);
          response.setHeader("WWW-Authenticate", authenticateHeader);
          response.setContentLength(0);
          
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/FormAuthenticator.java
  
  Index: FormAuthenticator.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/FormAuthenticator.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  import java.io.IOException;
  import java.security.Principal;
  import java.util.Enumeration;
  import java.util.Locale;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import org.apache.tomcat.HttpRequest;
  import org.apache.tomcat.HttpResponse;
  import org.apache.tomcat.Realm;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.deploy.LoginConfig;
  
  
  
  /**
   * An <b>Authenticator</b> and <b>Valve</b> implementation of FORM BASED
   * Authentication, as described in the Servlet API Specification, Version 2.2.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/07/26 22:08:20 $
   */
  
  public final class FormAuthenticator
      extends AuthenticatorBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Descriptive information about this implementation.
       */
      private static final String info =
  	"org.apache.tomcat.authenticator.FormAuthenticator/1.0";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Valve implementation.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Authenticate the user making this request, based on the specified
       * login configuration.  Return <code>true</code> if any specified
       * constraint has been satisfied, or <code>false</code> if we have
       * created a response challenge already.
       *
       * @param request Request we are processing
       * @param response Response we are creating
       * @param login Login configuration describing how authentication
       *              should be performed
       *
       * @exception IOException if an input/output error occurs
       */
      public boolean authenticate(HttpRequest request,
  				HttpResponse response,
  				LoginConfig config)
  	throws IOException {
  
  	// Have we already authenticated someone?
  	Principal principal =
  	    ((HttpServletRequest) request.getRequest()).getUserPrincipal();
  	if (principal != null)
  	    return (true);
  
  	// Have we got a cached authenticated Principal?
  	Session session = null;
  	if (cache)
  	    session = getSession(request);
  	if (session != null) {
  	    principal = session.getPrincipal();
  	    if (principal != null) {
  	        request.setAuthType(Constants.FORM_METHOD);
  		request.setUserPrincipal(principal);
  		return (true);
  	    }
  	}
  
  	// Acquire references to objects we will need to evaluate
  	HttpServletRequest hreq =
  	    (HttpServletRequest) request.getRequest();
  	HttpServletResponse hres =
  	    (HttpServletResponse) response.getResponse();
  	String contextPath = hreq.getContextPath();
  	String requestURI = hreq.getRequestURI();
  	response.setContext(request.getContext());
  
  	// Is this a request for the login page itself?  Test here to avoid
  	// displaying it twice (from the user's perspective) -- once because
  	// of the "save and redirect" and once because of the "restore and
  	// redirect" performed below.
  	if (requestURI.equals(contextPath + config.getLoginPage()))
  	    return (true);	// Display the login page in the usual manner
  
  	// Is this the action request from the login page?
  	boolean loginAction =
  	    requestURI.startsWith(contextPath) &&
  	    requestURI.endsWith(Constants.FORM_ACTION);
  
  	// No -- Save this request and redirect to the form login page
  	if (!loginAction) {
  	    session = getSession(request, true);
  	    saveRequest(request, session);
  	    request.setRequestURI(contextPath + config.getLoginPage());
  	    return (true);	// Display the login page in the usual manner
  	}
  
  	// Yes -- Validate the specified credentials and redirect
  	// to the error page if they are not correct
  	Realm realm = context.getRealm();
  	String username = hreq.getParameter(Constants.FORM_USERNAME);
  	String password = hreq.getParameter(Constants.FORM_PASSWORD);
  	principal = realm.authenticate(username, password);
  	if (principal == null) {
  	    request.setRequestURI(contextPath + config.getErrorPage());
  	    return (true);	// Display the error page in the usual manner
  	}
  
  
  	// Restore this request and redirect to the original request URI
  	request.setAuthType(Constants.FORM_METHOD);
  	request.setUserPrincipal(principal);
  	if (cache && (session != null))
  	    session.setPrincipal(principal);
  	if (restoreRequest(request, session))
  	    return (true);		// Perform the original request
  	else {
  	    hres.sendError(HttpServletResponse.SC_BAD_REQUEST);
  	    hres.flushBuffer();
  	    return (false);
  	}
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Restore the original request from information stored in our session.
       * If the original request is no longer present (because the session
       * timed out), return <code>false</code>; otherwise, return
       * <code>true</code>.
       *
       * @param request The request to be restored
       * @param session The session containing the saved information
       */
      private boolean restoreRequest(HttpRequest request, Session session) {
  
  	// Retrieve and remove the SavedRequest object from our session
  	SavedRequest saved = (SavedRequest)
  	    session.getSession().getAttribute(Constants.FORM_KEY);
  	session.getSession().removeAttribute(Constants.FORM_KEY);
  	if (saved == null)
  	    return (false);
  
  	// Modify our current request to reflect the original one
  	request.clearCookies();
  	Cookie cookies[] = saved.getCookies();
  	for (int i = 0; i < cookies.length; i++)
  	    request.addCookie(cookies[i]);
  	request.clearHeaders();
  	String names[] = saved.getHeaderNames();
  	for (int i = 0; i < names.length; i++) {
  	    String values[] = saved.getHeaderValues(names[i]);
  	    for (int j = 0; j < values.length; j++)
  		request.addHeader(names[i], values[j]);
  	}
  	request.clearLocales();
  	Locale locales[] = saved.getLocales();
  	for (int i = 0; i < locales.length; i++)
  	    request.addLocale(locales[i]);
  	request.setMethod(saved.getMethod());
  	request.setQueryString(saved.getQueryString());
  	request.setRequestURI(saved.getRequestURI());
  	return (true);
  
      }
  
  
      /**
       * Save the original request information into our session.
       *
       * @param request The request to be saved
       * @param session The session to contain the saved information
       */
      private void saveRequest(HttpRequest request, Session session) {
  
  	// Create and populate a SavedRequest object for this request
  	HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
  	SavedRequest saved = new SavedRequest();
  	Cookie cookies[] = hreq.getCookies();
  	if (cookies != null) {
  	    for (int i = 0; i < cookies.length; i++)
  		saved.addCookie(cookies[i]);
  	}
  	Enumeration names = hreq.getHeaderNames();
  	while (names.hasMoreElements()) {
  	    String name = (String) names.nextElement();
  	    Enumeration values = hreq.getHeaders(name);
  	    while (values.hasMoreElements()) {
  		String value = (String) values.nextElement();
  		saved.addHeader(name, value);
  	    }
  	}
  	Enumeration locales = hreq.getLocales();
  	while (locales.hasMoreElements()) {
  	    Locale locale = (Locale) locales.nextElement();
  	    saved.addLocale(locale);
  	}
  	saved.setMethod(hreq.getMethod());
  	saved.setQueryString(hreq.getQueryString());
  	saved.setRequestURI(hreq.getRequestURI());
  
  	// Stash the SavedRequest in our session for later use
  	session.getSession().setAttribute(Constants.FORM_KEY, saved);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  authenticator.alreadyStarted=Security Interceptor has already been started
  authenticator.forbidden=Access to the requested resource has been denied
  authenticator.notAuthenticated=Configuration error:  Cannot perform access control without an authenticated principal
  authenticator.notContext=Configuration error:  Must be attached to a Context
  authenticator.notStarted=Security Interceptor has not yet been started
  authenticator.userDataConstraint=This request violates a User Data constraint for this application
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/SavedRequest.java
  
  Index: SavedRequest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/SavedRequest.java,v 1.1 2000/07/26 22:08:20 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/07/26 22:08:20 $
   *
   * ====================================================================
   *
   * 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.tomcat.authenticator;
  
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Locale;
  import java.util.Vector;
  import javax.servlet.http.Cookie;
  import org.apache.tomcat.HttpRequest;
  import org.apache.tomcat.Session;
  
  
  /**
   * Object that saves the critical information from a request so that
   * form-based authentication can reproduce it once the user has been
   * authenticated.
   * <p>
   * <b>FIXME</b> - Currently, this object has no mechanism to save or
   * restore the data content of the request, so it will not support a
   * POST request triggering the authentication.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/07/26 22:08:20 $
   */
  
  public final class SavedRequest {
  
  
      /**
       * The set of Cookies associated with this Request.
       */
      private Vector cookies = new Vector();
  
      public void addCookie(Cookie cookie) {
  	cookies.addElement(cookie);
      }
  
      public Cookie[] getCookies() {
  	Cookie results[] = new Cookie[cookies.size()];
  	cookies.copyInto(results);
  	return (results);
      }
  
  
      /**
       * The set of Headers associated with this Request.  Each key is a header
       * name, while the value is a Vector containing one or more actual
       * values for this header.
       */
      private Hashtable headers = new Hashtable();
  
      public void addHeader(String name, String value) {
  	Vector values = (Vector) headers.get(name);
  	if (values == null) {
  	    values = new Vector();
  	    headers.put(name, values);
  	}
  	values.addElement(value);
      }
  
      public String[] getHeaderNames() {
  	Vector keys = new Vector();
  	Enumeration enum = headers.keys();
  	while (enum.hasMoreElements())
  	    keys.addElement(enum.nextElement());
  	String results[] = new String[keys.size()];
  	keys.copyInto(results);
  	return (results);
      }
  
      public String[] getHeaderValues(String name) {
  	Vector values = (Vector) headers.get(name);
  	if (values == null)
  	    return (new String[0]);
  	String results[] = new String[values.size()];
  	values.copyInto(results);
  	return (results);
      }
  
  
      /**
       * The set of Locales associated with this Request.
       */
      private Vector locales = new Vector();
  
      public void addLocale(Locale locale) {
  	locales.addElement(locale);
      }
  
      public Locale[] getLocales() {
  	Locale results[] = new Locale[locales.size()];
  	locales.copyInto(results);
  	return (results);
      }
  
  
      /**
       * The request method used on this Request.
       */
      private String method = null;
  
      public String getMethod() {
  	return (this.method);
      }
  
      public void setMethod(String method) {
  	this.method = method;
      }
  
  
      /**
       * The query string associated with this Request.
       */
      private String queryString = null;
  
      public String getQueryString() {
  	return (this.queryString);
      }
  
      public void setQueryString(String queryString) {
  	this.queryString = queryString;
      }
  
  
      /**
       * The request URI associated with this Request.
       */
      private String requestURI = null;
  
      public String getRequestURI() {
  	return (this.requestURI);
      }
  
      public void setRequestURI(String requestURI) {
  	this.requestURI = requestURI;
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/authenticator/package.html
  
  Index: package.html
  ===================================================================
  <body>
  
  <p>This package contains <code>Authenticator</code> implementations for the
  various supported authentication methods (BASIC, DIGEST, and FORM).  In
  addition, there is a convenience base class,
  <code>AuthenticatorBase</code>, for customized <code>Authenticator</code>
  implementations.</p>
  
  <p>If you are using the standard context configuration class
  (<code>org.apache.tomcat.startup.ContextConfig</code>) to configure the
  Authenticator associated with a particular context, you can register the Java
  class to be used for each possible authentication method by modifying the
  following Properties file:</p>
  <pre>
      src/share/org/apache/tomcat/startup/Authenticators.properties
  </pre>
  
  <p>Each of the standard implementations extends a common base class
  (<code>AuthenticatorBase</code>), which is configured by setting the
  following JavaBeans properties (with default values in square brackets):</p>
  <ul>
  <li><b>cache</b> - Should we cache authenticated Principals (thus avoiding
      per-request lookups in our underyling <code>Realm</code>) if this request
      is part of an HTTP session?  [true]</li>
  <li><b>debug</b> - Debugging detail level for this component.  [0]</li>
  </ul>
  
  <p>The standard authentication methods that are currently provided include:</p>
  <ul>
  <li><b>BasicAuthenticator</b> - Implements HTTP BASIC authentication, as
      described in RFC 2617.</li>
  <li><b>DigestAuthenticator</b> - Implements HTTP DIGEST authentication, as
      described in RFC 2617.</li>
  <li><b>FormAuthenticator</b> - Implements FORM-BASED authentication, as
      described in the Servlet API Specification, version 2.2.</li>
  </ul>
  
  </body>
  
  
  

Mime
View raw message