yoavs       2004/09/21 16:29:33

  Modified:    catalina/src/share/org/apache/catalina/realm
                        JAASCallbackHandler.java JAASRealm.java
                        LocalStrings.properties
               webapps/docs changelog.xml
  Log:
  Bugzilla 28631: JAASRealm enhancements to allow custom user and group principal 
classes (and use commons-logging)
  
  Revision  Changes    Path
  1.5       +35 -14    
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java
  
  Index: JAASCallbackHandler.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- JAASCallbackHandler.java  23 Jun 2004 13:51:37 -0000      1.4
  +++ JAASCallbackHandler.java  21 Sep 2004 23:29:33 -0000      1.5
  @@ -25,25 +25,38 @@
   import javax.security.auth.callback.PasswordCallback;
   import javax.security.auth.callback.UnsupportedCallbackException;
   
  +import org.apache.catalina.util.StringManager;
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   
   /**
  - * <p>Implementation of the JAAS <strong>CallbackHandler</code> interface,
  + * <p>Implementation of the JAAS <code>CallbackHandler</code> interface,
    * used to negotiate delivery of the username and credentials that were
    * specified to our constructor.  No interaction with the user is required
    * (or possible).</p>
    *
  + * <p>This <code>CallbackHandler</code> will pre-digest the supplied
  + * password, if required by the <code>&lt;Realm&gt;</code> element in 
  + * <code>server.xml</code>.</p>
  + * <p>At present, <code>JAASCallbackHandler</code> knows how to handle callbacks of
  + * type <code>javax.security.auth.callback.NameCallback</code> and
  + * <code>javax.security.auth.callback.PasswordCallback</code>.</p>
  + *
    * @author Craig R. McClanahan
  + * @author Andrew R. Jaquith
    * @version $Revision$ $Date$
    */
   
   public class JAASCallbackHandler implements CallbackHandler {
  -
  +    private static Log log = LogFactory.getLog(JAASCallbackHandler.class);
   
       // ------------------------------------------------------------ Constructor
   
   
       /**
        * Construct a callback handler configured with the specified values.
  +     * Note that if the <code>JAASRealm</code> instance specifies digested 
passwords,
  +     * the <code>password</code> parameter will be pre-digested here.
        *
        * @param realm Our associated JAASRealm instance
        * @param username Username to be authenticated with
  @@ -55,13 +68,26 @@
           super();
           this.realm = realm;
           this.username = username;
  -        this.password = password;
   
  +        if (realm.hasMessageDigest()) {
  +            this.password = realm.digest(password);
  +            if (log.isDebugEnabled()) {
  +                log.debug(sm.getString("jaasCallback.digestpassword", password, 
this.password));
  +            }
  +        }
  +        else {
  +            this.password = password;
  +        }
       }
   
   
       // ----------------------------------------------------- Instance Variables
   
  +    /**
  +     * The string manager for this package.
  +     */
  +    protected static final StringManager sm =
  +        StringManager.getManager(Constants.Package);
   
       /**
        * The password to be authenticated with.
  @@ -85,11 +111,11 @@
   
   
       /**
  -     * Retrieve the information requested in the provided Callbacks.  This
  -     * implementation only recognizes <code>NameCallback</code> and
  +     * Retrieve the information requested in the provided <code>Callbacks</code>.
  +     * This implementation only recognizes <code>NameCallback</code> and
        * <code>PasswordCallback</code> instances.
        *
  -     * @param callbacks The set of callbacks to be processed
  +     * @param callbacks The set of <code>Callback</code>s to be processed
        *
        * @exception IOException if an input/output error occurs
        * @exception UnsupportedCallbackException if the login method requests
  @@ -102,11 +128,11 @@
   
               if (callbacks[i] instanceof NameCallback) {
                   if (realm.getContainer().getLogger().isTraceEnabled())
  -                    realm.getContainer().getLogger().trace("Returning username " + 
username);
  +                    
realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", 
username));
                   ((NameCallback) callbacks[i]).setName(username);
               } else if (callbacks[i] instanceof PasswordCallback) {
                   if (realm.getContainer().getLogger().isTraceEnabled())
  -                    realm.getContainer().getLogger().trace("Returning password " + 
password);
  +                    
realm.getContainer().getLogger().trace(sm.getString("jaasCallback.password", 
password));
                   final char[] passwordcontents;
                   if (password != null) {
                       passwordcontents = password.toCharArray();
  @@ -118,11 +144,6 @@
               } else {
                   throw new UnsupportedCallbackException(callbacks[i]);
               }
  -
  -
           }
  -
       }
  -
  -
   }
  
  
  
  1.9       +177 -58   
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
  
  Index: JAASRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/JAASRealm.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- JAASRealm.java    20 Sep 2004 15:57:55 -0000      1.8
  +++ JAASRealm.java    21 Sep 2004 23:29:33 -0000      1.9
  @@ -22,7 +22,10 @@
   import java.security.acl.Group;
   import java.util.ArrayList;
   import java.util.Enumeration;
  +import java.util.HashMap;
   import java.util.Iterator;
  +import java.util.Map;
  +import java.util.List;
   
   import javax.security.auth.Subject;
   import javax.security.auth.login.AccountExpiredException;
  @@ -62,7 +65,7 @@
    * this Realm:</p>
    * <ul>
    * <li>The JAAS <code>LoginModule</code> is assumed to return a
  - *     <code>Subject with at least one <code>Principal</code> instance
  + *     <code>Subject</code> with at least one <code>Principal</code> instance
    *     representing the user himself or herself, and zero or more separate
    *     <code>Principals</code> representing the security roles authorized
    *     for this user.</li>
  @@ -87,10 +90,39 @@
    * <li>It is a configuration error for the JAAS login method to return a
    *     validated <code>Subject</code> without a <code>Principal</code> that
    *     matches the "user classes" list.</li>
  - * </ul>
  - *
  - * @author Craig R. McClanahan
  - * @author Yoav Shapira
  + * <li>By default, the enclosing Container's name serves as the
  + *     application name used to obtain the JAAS LoginContext ("Catalina" in
  + *     a default installation). Tomcat must be able to find an application
  + *     with this name in the JAAS configuration file. Here is a hypothetical
  + *     JAAS configuration file entry for a database-oriented login module that uses 
  + *     a Tomcat-managed JNDI database resource:
  + *     <blockquote><pre>Catalina {
  +org.foobar.auth.DatabaseLoginModule REQUIRED
  +    JNDI_RESOURCE=jdbc/AuthDB
  +  USER_TABLE=users
  +  USER_ID_COLUMN=id
  +  USER_NAME_COLUMN=name
  +  USER_CREDENTIAL_COLUMN=password
  +  ROLE_TABLE=roles
  +  ROLE_NAME_COLUMN=name
  +  PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
  +};</pre></blockquote></li>
  + * <li>To set the JAAS configuration file
  + *     location, set the <code>CATALINA_OPTS</code> environment variable
  + *     similar to the following:
  
+<blockquote><code>CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"</code></blockquote>
  + * </li>
  + * <li>As part of the login process, JAASRealm registers its own 
<code>CallbackHandler</code>,
  + *     called (unsurprisingly) <code>JAASCallbackHandler</code>. This handler 
supplies the 
  + *     HTTP requests's username and credentials to the user-supplied 
<code>LoginModule</code></li>
  + * <li>As with other <code>Realm</code> implementations, digested passwords are 
supported if
  + *     the <code>&lt;Realm&gt;</code> element in <code>server.xml</code> contains a 
  + *     <code>digest</code> attribute; <code>JAASCallbackHandler</code> will digest 
the password
  + *     prior to passing it back to the <code>LoginModule</code></li>  
  +* </ul>
  +*
  +* @author Craig R. McClanahan
  +* @author Yoav Shapira
    * @version $Revision$ $Date$
    */
   
  @@ -104,20 +136,20 @@
   
       /**
        * The application name passed to the JAAS <code>LoginContext</code>,
  -     * which uses it to select the set of relevant <code>LoginModules</code>.
  +     * which uses it to select the set of relevant <code>LoginModule</code>s.
        */
       protected String appName = null;
   
   
       /**
  -     * Descriptive information about this Realm implementation.
  +     * Descriptive information about this <code>Realm</code> implementation.
        */
       protected static final String info =
           "org.apache.catalina.realm.JAASRealm/1.0";
   
   
       /**
  -     * Descriptive information about this Realm implementation.
  +     * Descriptive information about this <code>Realm</code> implementation.
        */
       protected static final String name = "JAASRealm";
   
  @@ -125,7 +157,7 @@
       /**
        * The list of role class names, split out for easy processing.
        */
  -    protected ArrayList roleClasses = new ArrayList();
  +    protected List roleClasses = new ArrayList();
   
   
       /**
  @@ -138,7 +170,14 @@
       /**
        * The set of user class names, split out for easy processing.
        */
  -    protected ArrayList userClasses = new ArrayList();
  +    protected List userClasses = new ArrayList();
  +
  +     /**
  +      * Map associating each user <code>Principal</code> object
  +      * with an array of role <code>Principal</code>s. 
  +      * This Map is read when <code>hasRole</code> is called.
  +      */
  +     protected Map roleMap = new HashMap();
   
       /**
        * Whether to use context ClassLoader or default ClassLoader.
  @@ -152,15 +191,15 @@
   
       
       /**
  -     * setter for the appName member variable
  -     * @deprecated JAAS should use the Engine ( domain ) name and webpp/host 
overrides
  +     * setter for the <code>appName</code> member variable
  +     * @deprecated JAAS should use the <code>Engine</code> (domain) name and 
webpp/host overrides
        */
       public void setAppName(String name) {
           appName = name;
       }
       
       /**
  -     * getter for the appName member variable
  +     * getter for the <code>appName</code> member variable
        */
       public String getAppName() {
           return appName;
  @@ -201,7 +240,7 @@
       }
   
       /**
  -     * Comma-delimited list of <code>javax.security.Principal</code> classes
  +     * Comma-delimited list of <code>java.security.Principal</code> classes
        * that represent security roles.
        */
       protected String roleClassNames = null;
  @@ -210,8 +249,16 @@
           return (this.roleClassNames);
       }
   
  -    public void setRoleClassNames(String roleClassNames) {
  -        this.roleClassNames = roleClassNames;
  +     /**
  +      * Sets the list of comma-delimited classes that represent 
  +      * roles. The classes in the list must implement 
<code>java.security.Principal</code>.
  +      * When this accessor is called (for example, by a <code>Digester</code>
  +      * instance parsing the
  +      * configuration file), it will parse the class names and store the resulting
  +      * string(s) into the <code>ArrayList</code> field </code>roleClasses</code>.
  +      */
  +     public void setRoleClassNames(String roleClassNames) {
  +         this.roleClassNames = roleClassNames;
           roleClasses.clear();
           String temp = this.roleClassNames;
           if (temp == null) {
  @@ -233,7 +280,7 @@
   
   
       /**
  -     * Comma-delimited list of <code>javax.security.Principal</code> classes
  +     * Comma-delimited list of <code>java.security.Principal</code> classes
        * that represent individual users.
        */
       protected String userClassNames = null;
  @@ -242,6 +289,14 @@
           return (this.userClassNames);
       }
   
  +     /**
  +     * Sets the list of comma-delimited classes that represent individual
  +     * users. The classes in the list must implement 
<code>java.security.Principal</code>.
  +     * When this accessor is called (for example, by a <code>Digester</code>
  +     * instance parsing the
  +     * configuration file), it will parse the class names and store the resulting
  +     * string(s) into the <code>ArrayList</code> field </code>userClasses</code>.
  +     */
       public void setUserClassNames(String userClassNames) {
           this.userClassNames = userClassNames;
           userClasses.clear();
  @@ -268,7 +323,7 @@
   
   
       /**
  -     * Return the Principal associated with the specified username and
  +     * Return the <code>Principal</code> associated with the specified username and
        * credentials, if there is one; otherwise return <code>null</code>.
        *
        * If there are any errors with the JDBC connection, executing
  @@ -276,7 +331,7 @@
        * event is also logged, and the connection will be closed so that
        * a subsequent request will automatically re-open it.
        *
  -     * @param username Username of the Principal to look up
  +     * @param username Username of the <code>Principal</code> to look up
        * @param credentials Password or other credentials to use in
        *  authenticating this username
        */
  @@ -288,7 +343,7 @@
           if( appName==null ) appName="Tomcat";
   
           if( log.isDebugEnabled())
  -            log.debug("Authenticating " + appName + " " +  username);
  +            log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
   
           // What if the LoginModule is in the container class loader ?
           ClassLoader ocl = null;
  @@ -345,7 +400,7 @@
           }
   
           if( log.isDebugEnabled())
  -            log.debug("Getting principal " + subject);
  +            log.debug(sm.getString("jaasRealm.loginContextCreated", username));
   
           // Return the appropriate Principal for this authenticated Subject
           Principal principal = createPrincipal(username, subject);
  @@ -363,7 +418,53 @@
               return null;
           }
       }
  -
  +     
  +     /**
  +      * Returns <code>true</code> if the specified user <code>Principal</code> has 
the specified
  +      * security role, within the context of this <code>Realm</code>; otherwise 
return
  +      * <code>false</code>. This will be true when 
  +      * an associated role <code>Principal</code> can be found whose 
<code>getName</code>
  +      * method returns a <code>String</code> equalling the specified role.
  +      * @param principal <code>Principal</code> for whom the role is to be checked
  +      * @param role Security role to be checked
  +      */
  +     public boolean hasRole(Principal principal, String role) {
  +         if (log.isDebugEnabled()) {
  +             log.debug(sm.getString("jaasRealm.isInRole.start", 
principal.getName(), role));
  +         }
  +         
  +         if ((principal == null) || (role == null) ||
  +             (roleMap.get(principal) == null)) {
  +             if (log.isDebugEnabled()) {
  +                 log.debug(sm.getString("jaasRealm.isInRole.noPrincipalOrRole"));
  +             }
  +             return false;
  +         }
  +         
  +         List roles = (List)roleMap.get(principal);
  +         if (log.isDebugEnabled()) {
  +             log.debug(sm.getString("jaasRealm.isInRole.principalCached", 
String.valueOf(roles.size())));
  +         }
  +         
  +         for (Iterator it = roles.iterator(); it.hasNext();) {
  +             Principal possessedRole = (Principal)it.next();
  +             String possessedRoleName = possessedRole.getName();
  +             if (log.isDebugEnabled()) {
  +                 log.debug(sm.getString("jaasRealm.isInRole.possessesRole", 
possessedRole.getName()));
  +             }
  +             
  +             if (possessedRoleName.equals(role)) {
  +                 if (log.isDebugEnabled()) {
  +                     log.debug(sm.getString("jaasRealm.isInRole.match"));
  +                 }
  +                 return true;
  +             }
  +         }
  +         if (log.isDebugEnabled()) {
  +             log.debug(sm.getString("jaasRealm.isInRole.noMatch"));
  +         }
  +         return false;
  +     }
   
       // -------------------------------------------------------- Package Methods
   
  @@ -372,7 +473,7 @@
   
   
       /**
  -     * Return a short name for this Realm implementation.
  +     * Return a short name for this <code>Realm</code> implementation.
        */
       protected String getName() {
   
  @@ -392,7 +493,7 @@
   
   
       /**
  -     * Return the Principal associated with the given user name.
  +     * Return the <code>Principal</code> associated with the given user name.
        */
       protected Principal getPrincipal(String username) {
   
  @@ -402,58 +503,76 @@
   
   
       /**
  -     * Construct and return a <code>java.security.Principal</code> instance
  -     * representing the authenticated user for the specified Subject.  If no
  -     * such Principal can be constructed, return <code>null</code>.
  -     *
  -     * @param subject The Subject representing the logged in user
  +     * Identify and return a <code>java.security.Principal</code> instance
  +     * representing the authenticated user for the specified <code>Subject</code>.
  +     * The Principal is constructed by scanning the list of Principals returned
  +     * by the JAASLoginModule. The first <code>Principal</code> object that matches
  +     * one of the class names supplied as a "user class" is the user Principal.
  +     * This object is returned to tha caller.
  +     * Any remaining principal objects returned by the LoginModules are mapped to  
  +     * roles, but only if their respective classes match one of the "role class" 
classes. 
  +     * If a user Principal cannot be constructed, return <code>null</code>.
  +     * @param subject The <code>Subject</code> representing the logged-in user
        */
       protected Principal createPrincipal(String username, Subject subject) {
           // Prepare to scan the Principals for this Subject
           String password = null; // Will not be carried forward
  -        ArrayList roles = new ArrayList();
  +
  +        List roles = new ArrayList();
  +        Principal userPrincipal = null;
   
           // Scan the Principals for this Subject
           Iterator principals = subject.getPrincipals().iterator();
           while (principals.hasNext()) {
               Principal principal = (Principal) principals.next();
  -            // No need to look further - that's our own stuff
  -            if( principal instanceof GenericPrincipal ) {
  -                if( log.isDebugEnabled() )
  -                    log.debug("Found old GenericPrincipal " + principal );
  -                return principal;
  -            }
  +
               String principalClass = principal.getClass().getName();
  -            if( log.isDebugEnabled() )
  -                log.info("Principal: " + principalClass + " " + principal);
   
  -            if (userClasses.contains(principalClass)) {
  -                // Override the default - which is the original user, accepted by
  -                // the friendly LoginManager
  -                username = principal.getName();
  +            if( log.isDebugEnabled() ) {
  +                log.debug(sm.getString("jaasRealm.checkPrincipal", principal, 
principalClass));
  +            }
  +
  +            if (userPrincipal == null && userClasses.contains(principalClass)) {
  +                userPrincipal = principal;
  +                if( log.isDebugEnabled() ) {
  +                    log.debug(sm.getString("jaasRealm.userPrincipalSuccess", 
principal.getName()));
  +                }
               }
  +            
               if (roleClasses.contains(principalClass)) {
                   roles.add(principal.getName());
               }
  -            // Same as Jboss - that's a pretty clean solution
  -            if( (principal instanceof Group) &&
  -                 "Roles".equals( principal.getName())) {
  -                Group grp=(Group)principal;
  -                Enumeration en=grp.members();
  -                while( en.hasMoreElements() ) {
  -                    Principal roleP=(Principal)en.nextElement();
  -                    roles.add( roleP.getName());
  -                }
   
  +            if (roleClasses.contains(principalClass)) {
  +                roles.add(principal);
  +                if( log.isDebugEnabled() ) {
  +                    log.debug(sm.getString("jaasRealm.rolePrincipalAdd", 
principal.getName()));
  +                }
               }
           }
   
  -        // Create the resulting Principal for our authenticated user
  -        if (username != null) {
  -            return (new GenericPrincipal(this, username, password, roles));
  +        // Print failure message if needed
  +        if (userPrincipal == null) {
  +            if (log.isDebugEnabled()) {
  +                log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
  +                log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
  +            }
           } else {
  -            return (null);
  +            if (roles.size() == 0) {
  +                if (log.isDebugEnabled()) {
  +                    log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
  +                }
  +            } else {
  +                roleMap.put(userPrincipal, roles);
  +                if (log.isDebugEnabled()) {
  +                    log.debug(sm.getString("jaasRealm.rolePrincipalSuccess", 
String.valueOf(roles.size())));
  +                    log.debug(sm.getString("jaasRealm.cachePrincipal", 
userPrincipal.getName(), String.valueOf(roles.size())));
  +                }
  +            }
           }
  +
  +        // Return the resulting Principal for our authenticated user
  +        return userPrincipal;
       }
   
        /**
  @@ -488,7 +607,7 @@
   
       /**
        *
  -     * Prepare for active use of the public methods of this Component.
  +     * Prepare for active use of the public methods of this <code>Component</code>.
        *
        * @exception LifecycleException if this component detects a fatal error
        *  that prevents it from being started
  @@ -502,7 +621,7 @@
   
   
       /**
  -     * Gracefully shut down active use of the public methods of this Component.
  +     * Gracefully shut down active use of the public methods of this 
<code>Component</code>.
        *
        * @exception LifecycleException if this component detects a fatal error
        *  that needs to be reported
  
  
  
  1.7       +27 -6     
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- LocalStrings.properties   3 Jul 2004 04:16:41 -0000       1.6
  +++ LocalStrings.properties   21 Sep 2004 23:29:33 -0000      1.7
  @@ -4,12 +4,33 @@
   
   # package org.apache.catalina.realm
   
  -jaasRealm.accountExpired=Username {0} NOT authenticated due to expired account
  -jaasRealm.authenticateSuccess=Username {0} successfully authenticated
  -jaasRealm.credentialExpired=Username {0} NOT authenticated due to expired credential
  -jaasRealm.failedLogin=Username {0} NOT authenticated due to failed login
  -jaasRealm.loginException=Login exception authenticating username {0}
  +jaasRealm.beginLogin=JAASRealm login requested for username "{0}" using 
LoginContext for application "{1}"
  +jaasRealm.accountExpired=Username "{0}" NOT authenticated due to expired account
  +jaasRealm.authenticateFailure=Username "{0}" NOT successfully authenticated
  +jaasRealm.authenticateSuccess=Username "{0}" successfully authenticated as 
Principal "{1}" -- Subject was created too
  +jaasRealm.credentialExpired=Username "{0}" NOT authenticated due to expired 
credential
  +jaasRealm.failedLogin=Username "{0}" NOT authenticated due to failed login
  +jaasRealm.loginException=Login exception authenticating username "{0}"
   jaasRealm.unexpectedError=Unexpected error
  +jaasRealm.loginContextCreated=JAAS LoginContext created for username "{0}"
  +jaasRealm.userPrincipalSuccess=Subject for username "{0}" returned user Principal 
"{1}"
  +jaasRealm.userPrincipalFailure=Subject for username "{0}" did not return a valid 
user Principal
  +jaasRealm.cachePrincipal=User Principal "{0}" cached; has {1} role Principal(s)
  +jaasRealm.checkPrincipal=Checking Principal "{0}" [{1}]
  +jaasRealm.userPrincipalSuccess=Principal "{0}" is a valid user class. We will use 
this as the user Principal.
  +jaasRealm.userPrincipalFailure=No valid user Principal found
  +jaasRealm.rolePrincipalAdd=Adding role Principal "{0}" to this user Principal\'s 
roles
  +jaasRealm.rolePrincipalSuccess={0} role Principal(s) found
  +jaasRealm.rolePrincipalFailure=No valid role Principals found.
  +jaasRealm.isInRole.start=Checking if user Principal "{0}" possesses role "{1}"
  +jaasRealm.isInRole.noPrincipalOrRole=No roles Principals found. User Principal or 
Subject is null, or user Principal not in cache
  +jaasRealm.isInRole.principalCached=User Principal has {0} role Principal(s)
  +jaasRealm.isInRole.possessesRole=User Principal has a role Principal called "{0}"
  +jaasRealm.isInRole.match=Matching role Principal found.
  +jaasRealm.isInRole.noMatch=Matching role Principal NOT found.
  +jaasCallback.digestpassword=Digested password "{0}" as "{1}"
  +jaasCallback.username=Returned username "{0}"
  +jaasCallback.password=Returned password "{0}"
   jdbcRealm.authenticateFailure=Username {0} NOT successfully authenticated
   jdbcRealm.authenticateSuccess=Username {0} successfully authenticated
   jdbcRealm.close=Exception closing database connection
  
  
  
  1.114     +3 -0      jakarta-tomcat-catalina/webapps/docs/changelog.xml
  
  Index: changelog.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-catalina/webapps/docs/changelog.xml,v
  retrieving revision 1.113
  retrieving revision 1.114
  diff -u -r1.113 -r1.114
  --- changelog.xml     21 Sep 2004 19:36:11 -0000      1.113
  +++ changelog.xml     21 Sep 2004 23:29:33 -0000      1.114
  @@ -48,6 +48,9 @@
         <fix>
           <bug>31277</bug>: Clarified automatic application deployment section of 
Host configuration page. (yoavs)
         </fix>
  +     <fix> 
  +       <bug>28631</bug>: JAASRealm enhancements to support custom user, role class 
names, use Commons-Logging. (yoavs) 
  +     </fix> 
       </changelog>
     </subsection>
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to