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/04/18 22:41:24 UTC

cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm Constants.java LocalStrings.properties MemoryRealm.java

craigmcc    00/04/18 13:41:23

  Added:       proposals/catalina/src/share/org/apache/tomcat/realm
                        Constants.java LocalStrings.properties
                        MemoryRealm.java
  Log:
  Add a Realm implementation that is compatible with the
  "conf/tomcat-users.xml" file currently supported by Tomcat 3.1's
  SecurityCheck class.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm/Constants.java
  
  Index: Constants.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm/Constants.java,v 1.1 2000/04/18 20:41:22 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/04/18 20:41:22 $
   *
   * ====================================================================
   *
   * 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.realm;
  
  
  /**
   * Manifest constants for this Java package.
   *
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/04/18 20:41:22 $
   */
  
  public final class Constants {
  
      public static final String Package = "org.apache.tomcat.realm";
  
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  memoryRealm.alreadyStarted=This Realm has already been started
  memoryRealm.load.exists=Memory realm file {0} does not exist
  memoryRealm.notStarted=This Realm has not yet been started
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm/MemoryRealm.java
  
  Index: MemoryRealm.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/realm/MemoryRealm.java,v 1.1 2000/04/18 20:41:22 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/04/18 20:41:22 $
   *
   * ====================================================================
   *
   * 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.realm;
  
  
  import java.beans.PropertyChangeListener;
  import java.beans.PropertyChangeSupport;
  import java.security.Principal;
  import java.io.File;
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Vector;
  import org.apache.tomcat.Container;
  import org.apache.tomcat.Lifecycle;
  import org.apache.tomcat.LifecycleEvent;
  import org.apache.tomcat.LifecycleException;
  import org.apache.tomcat.LifecycleListener;
  import org.apache.tomcat.Realm;
  import org.apache.tomcat.util.LifecycleSupport;
  import org.apache.tomcat.util.StringManager;
  import org.apache.tomcat.util.xml.SaxContext;
  import org.apache.tomcat.util.xml.XmlAction;
  import org.apache.tomcat.util.xml.XmlMapper;
  import org.xml.sax.AttributeList;
  
  
  /**
   * Simple implementation of <b>Realm</b> that reads an XML file to configure
   * the valid users, passwords, and roles.  The file format (and default file
   * location) are identical to those currently supported by Tomcat 3.X.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/04/18 20:41:22 $
   */
  
  public final class MemoryRealm
      implements Lifecycle, Realm {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The Container with which this Realm is associated.
       */
      private Container container = null;
  
  
      /**
       * Descriptive information about this Realm implementation.
       */
      private static final String info =
  	"org.apache.tomcat.realm.MemoryRealm/1.0";
  
  
      /**
       * The lifecycle event support for this component.
       */
      private LifecycleSupport lifecycle = new LifecycleSupport(this);
  
  
      /**
       * The pathname (absolute or relative to Tomcat's current working
       * directory) of the XML file containing our database information.
       */
      private String pathname = "conf/tomcat-users.xml";
  
  
      /**
       * The set of valid Principals for this Realm, keyed by user name.
       */
      private Hashtable principals = new Hashtable();
  
  
      /**
       * Map role names to Vectors containing the associated Principals.
       */
      private Hashtable roles = new Hashtable();
  
  
      /**
       * The string manager for this package.
       */
      private static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      /**
       * Has this component been started?
       */
      private boolean started = false;
  
  
      /**
       * The property change support for this component.
       */
      private PropertyChangeSupport support = new PropertyChangeSupport(this);
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the Container with which this Realm has been associated.
       */
      public Container getContainer() {
  
  	return (container);
  
      }
  
  
      /**
       * Set the Container with which this Realm has been associated.
       *
       * @param container The associated Container
       */
      public void setContainer(Container container) {
  
  	Container oldContainer = this.container;
  	this.container = container;
  	support.firePropertyChange("container", oldContainer, this.container);
  
      }
  
  
      /**
       * Return descriptive information about this Realm implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
  
  	return (info);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Add a property change listener to this component.
       *
       * @param listener The listener to add
       */
      public void addPropertyChangeListener(PropertyChangeListener listener) {
  
  	support.addPropertyChangeListener(listener);
  
      }
  
  
      /**
       * Return the Principal associated with the specified username and
       * credentials, if there is one; otherwise return <code>null</code>.
       *
       * @param username Username of the Principal to look up
       * @param credentials Password or other credentials to use in
       *  authenticating this username
       */
      public Principal authenticate(String username, String credentials) {
  
  	MemoryRealmPrincipal principal =
  	    (MemoryRealmPrincipal) principals.get(username);
  	if ((principal != null) &&
  	    (credentials.equals(principal.getPassword())))
  	    return (principal);
  	else
  	    return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the specified username and
       * credentials, if there is one; otherwise return <code>null</code>.
       *
       * @param username Username of the Principal to look up
       * @param credentials Password or other credentials to use in
       *  authenticating this username
       */
      public Principal authenticate(String username, byte[] credentials) {
  
  	return (authenticate(username, credentials.toString()));
  
      }
  
  
      /**
       * Return <code>true</code> if the specified Principal has the specified
       * security role, within the context of this Realm; otherwise return
       * <code>false</code>.
       *
       * @param principal Principal for whom the role is to be checked
       * @param role Security role to be checked
       */
      public boolean hasRole(Principal principal, String role) {
  
  	MemoryRealmPrincipal realPrincipal =
  	    (MemoryRealmPrincipal) principals.get(principal.getName());
  	if (realPrincipal == null)
  	    return (false);
  	String name = realPrincipal.getName();
  	Vector users = (Vector) roles.get(role);
  	if (users == null)
  	    return (false);
  	Enumeration items = users.elements();
  	while (items.hasMoreElements()) {
  	    MemoryRealmPrincipal item =
  		(MemoryRealmPrincipal) items.nextElement();
  	    if (name.equals(item.getName()))
  		return (true);
  	}
  	return (false);
  
      }
  
  
      /**
       * Remove a property change listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removePropertyChangeListener(PropertyChangeListener listener) {
  
  	support.removePropertyChangeListener(listener);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Add a new user to the in-memory database.
       *
       * @param username User's username
       * @param password User's password (clear text)
       * @param roles Comma-delimited set of roles associated with this user
       */
      void addUser(String username, String password, String roles) {
  
  	MemoryRealmPrincipal principal =
  	    new MemoryRealmPrincipal(username, password);
  	principals.put(username, principal);
  
  	roles += ",";
  	while (true) {
  	    int comma = roles.indexOf(",");
  	    if (comma < 0)
  		break;
  	    String role = roles.substring(0, comma).trim();
  	    Vector users = (Vector) this.roles.get(role);
  	    if (users == null) {
  		users = new Vector();
  		this.roles.put(role, users);
  	    }
  	    users.addElement(role);
  	    roles = roles.substring(comma + 1);
  	}
  
      }
  
  
      // ------------------------------------------------------ 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 active use of the public methods of this Component.
       *
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception LifecycleException if this component detects a fatal error
       *  that prevents it from being started
       */
      public synchronized void start() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (started)
  	    throw new LifecycleException
  		(sm.getString("memoryRealm.alreadyStarted"));
  	started = true;
  	lifecycle.fireLifecycleEvent(START_EVENT, null);
  
  	// Validate the existence of our database file
  	// FIXME - Resolve relative pathname against tomcat home?
  	File file = new File(pathname);
  	if (!file.exists())
  	    throw new LifecycleException
  		(sm.getString("memoryRealm.load.exist", pathname));
  
  	// Load the contents of the database file
  	XmlMapper mapper = new XmlMapper();
  	mapper.addRule("tomcat-users/user", new MemoryRealmUserAction());
  	try {
  	    mapper.readXml(file, this);
  	} catch (Exception e) {
  	    throw new LifecycleException("MemoryRealm.start.readXml: " + e, e);
  	}
  
      }
  
  
      /**
       * Gracefully shut down active use of the public methods 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 synchronized void stop() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (!started)
  	    throw new LifecycleException
  		(sm.getString("memoryRealm.notStarted"));
  	started = false;
  	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  
  	// No shutdown activities required
  
      }
  
  
  }
  
  
  /**
   * Private class representing an individual user's Principal object.
   */
  
  final class MemoryRealmPrincipal implements Principal {
  
      /**
       * The username for this Principal.
       */
      private String username = null;
  
  
      /**
       * The password for this Principal.
       */
      private String password = null;
  
  
      /**
       * Construct a new MemoryRealmPrincipal instance.
       *
       * @param username The username for this Principal
       * @param password The password for this Principal
       */
      public MemoryRealmPrincipal(String username, String password) {
  
  	this.username = username;
  	this.password = password;
  
      }
  
  
      /**
       * Return the name of this Principal.
       */
      public String getName() {
  
  	return (username);
  
      }
  
  
      /**
       * Return the password of this Principal.
       */
      public String getPassword() {
  
  	return (password);
  
      }
  
  
  }
  
  
  /**
   * Private class used when parsing the XML database file.
   */
  final class MemoryRealmUserAction extends XmlAction {
  
  
      /**
       * Process a <code>&lt;user&gt;</code> element from the XML database file.
       *
       * @param context The SAX context within which this element was encountered
       */
      public void start(SaxContext context) throws Exception {
  
  	int top = context.getTagCount() - 1;
  	AttributeList attributes = context.getAttributeList(top);
  	String username = attributes.getValue("name");
  	String password = attributes.getValue("password");
  	String roles = attributes.getValue("roles");
  
  	MemoryRealm realm = (MemoryRealm) context.getRoot();
  	realm.addUser(username, password, roles);
  
      }
  
  }