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...@apache.org on 2002/01/20 04:16:35 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm UserDatabaseRealm.java

craigmcc    02/01/19 19:16:35

  Modified:    catalina/src/conf server.xml
  Added:       catalina/src/share/org/apache/catalina/realm
                        UserDatabaseRealm.java
  Log:
  Add a new realm that knows how to authenticate against a UserDatabase
  object that is configured in the global resources.  This provides
  equivalent behavior to the old MemoryRealm, but allows the database
  to be edited and saved at the same time.
  
  Modify server.xml as follows:
  
  * Define a resource for the MemoryUserDatabase implementation,
    configuring the relative pathname of the XML file containing the data,
    under name "catalina/UserDatabase" in the global JNDI resources.
  
  * Change the default <Realm> to an instance of UserDatabaseRealm
    that uses this exact same UserDatabase instance (identified by
    the resource name being "catalina/UserDatabase" and matching the
    global JNDI resource name).
  
  * Add a commented-out example of how you would define a resource link
    to make the user database available as a JNDI-accessible object to
    a web application.  Note that an application can *not* do this itself
    (in web.xml -- it must be deliberately enabled by editing server.xml).
  
  Doc updates to cover all this stuff are coming soon.
  
  Revision  Changes    Path
  1.50      +49 -0     jakarta-tomcat-4.0/catalina/src/conf/server.xml
  
  Index: server.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/conf/server.xml,v
  retrieving revision 1.49
  retrieving revision 1.50
  diff -u -r1.49 -r1.50
  --- server.xml	17 Jan 2002 20:16:53 -0000	1.49
  +++ server.xml	20 Jan 2002 03:16:35 -0000	1.50
  @@ -21,7 +21,27 @@
   
     <!-- Global JNDI resources -->
     <GlobalNamingResources>
  +
  +    <!-- Test entry for demonstration purposes -->
       <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
  +
  +    <!-- Editable user database that can also be used by
  +         UserDatabaseRealm to authenticate users -->
  +    <Resource name="catalina/UserDatabase" auth="Container"
  +              type="org.apache.catalina.UserDatabase"
  +       description="User database that can be updated and saved">
  +    </Resource>
  +    <ResourceParams name="catalina/UserDatabase">
  +      <parameter>
  +        <name>factory</name>
  +        <value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
  +      </parameter>
  +      <parameter>
  +        <name>pathname</name>
  +        <value>conf/tomcat-users.xml</value>
  +      </parameter>
  +    </ResourceParams>
  +
     </GlobalNamingResources>
   
     <!-- A "Service" is a collection of one or more "Connectors" that share
  @@ -139,7 +159,18 @@
   
         <!-- Because this Realm is here, an instance will be shared globally -->
   
  +      <!-- This Realm uses the UserDatabase configured in the global JNDI
  +           resources under the key "catalina/UserDatabase".  Any edits
  +           that are performed against this UserDatabase are immediately
  +           available for use by the Realm.  -->
  +      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
  +                 debug="0" resourceName="catalina/UserDatabase"/>
  +
  +      <!-- Comment out the old realm but leave here for now in case we
  +           need to go back quickly -->
  +<!--
         <Realm className="org.apache.catalina.realm.MemoryRealm" />
  +-->
   
         <!-- Replace the above Realm with one of the following to get a Realm
              stored in a database and accessed via JDBC -->
  @@ -224,6 +255,24 @@
             <Ejb   name="ejb/EmplRecord" type="Entity"
                    home="com.wombat.empl.EmployeeRecordHome"
                  remote="com.wombat.empl.EmployeeRecord"/>
  +
  +          <!-- If you wanted the examples app to be able to edit the
  +               user database, you would uncomment the following entry.
  +               Of course, you would want to enable security on the
  +               application as well, so this is not done by default!
  +               The database object could be accessed like this:
  +
  +               Context initCtx = new InitialContext();
  +               Context envCtx = (Context) initCtx.lookup("java:comp/env");
  +               UserDatabase database =
  +                    (UserDatabase) envCtx.lookup("userDatabase");
  +          -->
  +<!--
  +          <ResourceLink name="userDatabase" global="catalina/UserDatabase"
  +                        type="org.apache.catalina.UserDatabase"/>
  +-->
  +
  +
             <!-- PersistentManager: Uncomment the section below to test Persistent 
   		       Sessions.
                            
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java
  
  Index: UserDatabaseRealm.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java,v 1.1 2002/01/20 03:16:35 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2002/01/20 03:16:35 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.catalina.realm;
  
  
  import java.security.Principal;
  import java.util.ArrayList;
  import java.util.Iterator;
  import javax.naming.Context;
  import org.apache.catalina.Container;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Engine;
  import org.apache.catalina.Group;
  import org.apache.catalina.Logger;
  import org.apache.catalina.Realm;
  import org.apache.catalina.Server;
  import org.apache.catalina.User;
  import org.apache.catalina.UserDatabase;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.StringManager;
  import org.apache.commons.digester.Digester;
  
  
  /**
   * <p>Implementation of {@link Realm} that is based on an implementation of
   * {@link UserDatabase} made available through the global JNDI resources
   * configured for this instance of Catalina.  Set the <code>resourceName</code>
   * parameter to the global JNDI resources name for the configured instance
   * of <code>UserDatabase</code> that we should consult.</p>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2002/01/20 03:16:35 $
   * @since 4.1
   */
  
  public class UserDatabaseRealm
      extends RealmBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The <code>UserDatabase</code> we will use to authenticate users
       * and identify associated roles.
       */
      protected UserDatabase database = null;
  
  
      /**
       * Descriptive information about this Realm implementation.
       */
      protected final String info =
          "org.apache.catalina.realm.UserDatabaseRealm/1.0";
  
  
      /**
       * Descriptive information about this Realm implementation.
       */
      protected static final String name = "UserDatabaseRealm";
  
  
      /**
       * The global JNDI name of the <code>UserDatabase</code> resource
       * we will be utilizing.
       */
      protected String resourceName = "catalina/UserDatabase";
  
  
      /**
       * The string manager for this package.
       */
      private static StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * 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;
  
      }
  
  
      /**
       * Return the global JNDI name of the <code>UserDatabase</code> resource
       * we will be using.
       */
      public String getResourceName() {
  
          return resourceName;
  
      }
  
  
      /**
       * Set the global JNDI name of the <code>UserDatabase</code> resource
       * we will be using.
       *
       * @param resourceName The new global JNDI name
       */
      public void setResourceName(String name) {
  
          this.resourceName = resourceName;
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * 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) {
  
          // Does a user with this username exist?
          User user = database.findUser(username);
          if (user == null) {
              return (null);
          }
  
          // Do the credentials specified by the user match?
          // FIXME - Update all realms to support encoded passwords
          boolean validated = false;
          if (hasMessageDigest()) {
              // Hex hashes should be compared case-insensitive
              validated = (digest(credentials)
                           .equalsIgnoreCase(user.getPassword()));
          } else {
              validated =
                  (digest(credentials).equals(user.getPassword()));
          }
          if (!validated) {
              if (debug >= 2) {
                  log(sm.getString("userDatabaseRealm.authenticateFailure",
                                   username));
              }
              return (null);
          }
  
          // Construct a GenericPrincipal that represents this user
          if (debug >= 2) {
              log(sm.getString("userDatabaseRealm.authenticateSuccess",
                               username));
          }
          ArrayList combined = new ArrayList();
          Iterator roles = user.getRoles();
          while (roles.hasNext()) {
              String role = (String) roles.next();
              if (!combined.contains(role)) {
                  combined.add(role);
              }
          }
          Iterator groups = user.getGroups();
          while (groups.hasNext()) {
              Group group = (Group) groups.next();
              roles = group.getRoles();
              while (roles.hasNext()) {
                  String role = (String) roles.next();
                  if (!combined.contains(role)) {
                      combined.add(role);
                  }
              }
          }
          return (new GenericPrincipal(this, user.getUsername(),
                                       user.getPassword(), combined));
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return a short name for this Realm implementation.
       */
      protected String getName() {
  
          return (this.name);
  
      }
  
  
      /**
       * Return the password associated with the given principal's user name.
       */
      protected String getPassword(String username) {
  
          return (null);
  
      }
  
  
      /**
       * Return the Principal associated with the given user name.
       */
      protected Principal getPrincipal(String username) {
  
          return (null);
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * 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 {
  
          // Acquire a reference to the UserDatabase object we will be using
          Server server = null;
          Container parent = container;
          while (parent.getParent() != null) {
              parent = parent.getParent();
          }
          if (!(parent instanceof Engine)) {
              throw new LifecycleException
                  (sm.getString("userDatabaseRealm.noEngine"));
          } else {
              server = ((Engine) parent).getService().getServer();
          }
          // FIXME - getGlobalNamingContext() should be on Server interface
          Context global =
              ((org.apache.catalina.core.StandardServer) server).
              getGlobalNamingContext();
          if (global == null) {
              throw new LifecycleException
                  (sm.getString("userDatabaseRealm.noGlobal"));
          }
          try {
              database = (UserDatabase) global.lookup(resourceName);
          } catch (Throwable e) {
              log(sm.getString("userDatabaseRealm.lookup", resourceName), e);
              database = null;
          }
          if (database == null) {
              throw new LifecycleException
                  (sm.getString("userDatabaseRealm.noDatabase", resourceName));
          }
  
          // Perform normal superclass initialization
          super.start();
  
      }
  
  
      /**
       * 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 {
  
          // Perform normal superclass finalization
          super.stop();
  
          // Release reference to our user database
          database = null;
  
      }
  
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>