funkman     2003/09/04 12:59:47

  Modified:    catalina build.xml
               webapps/tomcat-docs realm-howto.xml
               catalina/src/share/org/apache/catalina/realm JNDIRealm.java
  Added:       catalina/src/test/org/apache/catalina/realm
                        JNDIRealmTestCase.java
  Log:
  Per http://marc.theaimsgroup.com/?l=tomcat-dev&m=106254937722504&w=2
  
  Allow Multiple user patterns in JNDIRealm and doc patch.
  
  Patch provided by Jeff Tulley  (jtulley at novell.com)
  
  Revision  Changes    Path
  1.133     +11 -1     jakarta-tomcat-4.0/catalina/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/build.xml,v
  retrieving revision 1.132
  retrieving revision 1.133
  diff -u -r1.132 -r1.133
  --- build.xml 12 Mar 2003 21:38:05 -0000      1.132
  +++ build.xml 4 Sep 2003 19:59:46 -0000       1.133
  @@ -979,7 +979,7 @@
     <!-- ==================== TEST: Execute Unit Tests ====================== -->
     <target name="test" if="junit.present"
      description="Run all unit test cases"
  -   depends="build-tests,test-dir-context,test-util">
  +   depends="build-tests,test-dir-context,test-realm,test-util">
     </target>
   
     <target name="test-dir-context" if="junit.present">
  @@ -1004,6 +1004,16 @@
       </java>
       <delete file="${test.webapp.war}"/>
   
  +  </target>
  +
  +  <target name="test-realm" if="junit.present">
  +
  +    <echo message="Running Realm tests"/>
  +    <java classname="${test.runner}" fork="yes"
  +        failonerror="${test.failonerror}">
  +      <arg value="org.apache.catalina.realm.JNDIRealmTestCase"/>
  +      <classpath refid="test.classpath"/>
  +    </java>
     </target>
   
     <target name="test-util" if="junit.present">
  
  
  
  1.13      +56 -14    jakarta-tomcat-4.0/webapps/tomcat-docs/realm-howto.xml
  
  Index: realm-howto.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/webapps/tomcat-docs/realm-howto.xml,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- realm-howto.xml   7 May 2003 15:56:00 -0000       1.12
  +++ realm-howto.xml   4 Sep 2003 19:59:47 -0000       1.13
  @@ -362,7 +362,7 @@
       <li>Password to be recognized by Tomcat when the user logs in.
           This value may in cleartext or digested - see below for more
           information.</li>
  -    </ul></li>    
  +    </ul></li>
   <li>There must be a table, referenced below as the <em>user roles</em> table,
       that contains one row for every valid role that is assigned to a
       particular user.  It is legal for a user to have zero, one, or more than
  @@ -373,13 +373,13 @@
       <li>Username to be recognized by Tomcat (same value as is specified
           in the <em>users</em> table).</li>
       <li>Role name of a valid role associated with this user.</li>
  -    </ul></li>    
  +    </ul></li>
   </ul>
   
   <h3>Quick Start</h3>
  -                  
  +
   <p>To set up Tomcat to use DataSourceRealm, you will need to follow these steps:</p>
  -<ol>              
  +<ol>
   <li>If you have not yet done so, create tables and columns in your database
       that conform to the requirements described above.</li>
   <li>Configure a database username and password for use by Tomcat, that has
  @@ -418,7 +418,7 @@
       generate more detailed output.  If not specified, the default
       debugging detail level is zero (0).</p>
     </attribute>
  -    
  +
     <attribute name="digest" required="false">
       <p>The digest algorithm used to store passwords in non-plaintext formats.
       Valid values are those accepted for the algorithm name by the
  @@ -426,18 +426,18 @@
       <a href="#Digested Passwords">Digested Passwords</a> for more
       information.  If not specified, passwords are stored in clear text.</p>
     </attribute>
  -    
  +
     <attribute name="roleNameCol" required="true">
       <p>The name of the column, in the <em>user roles</em> table, that
       contains the name of a role assigned to this user.</p>
     </attribute>
  -    
  +
     <attribute name="userCredCol" required="true">
       <p>The name of the column, in the <em>users</em> table, that contains
       the password for this user (either in clear text, or digested if the
       <code>digest</code> attribute is set).</p>
     </attribute>
  -    
  +
     <attribute name="userNameCol" required="true">
       <p>The name of the column, in the <em>users</em> and <em>user roles</em>
       tables, that contains the username of this user.</p>
  @@ -559,11 +559,19 @@
   attribute containing the username that is presented for
   authentication.</p>
   
  -<p>Often the distinguished name of the user's entry contains the
  -username presented for authentication but is otherwise the same for
  -all users. In this case the <strong>userPattern</strong> attribute may
  -be used to specify the DN, with "{0}" marking where
  -the username should be substituted.</p>
  +<p>There are multiple options for specifying where to look for users.
  +One is through the use of <strong>userPattern</strong>.  This is set
  +to the distinguished name of the user entry, but with "{0}" marking
  +where the username should be substituted.  If you want Tomcat to
  +search for the username in multiple places, you can supply multiple
  +locations in the <strong>userPattern</strong>.  This is done by
  +surrounding each separate location with parentheses.  For example,
  +"(cn={0},ou=users1,o=myorg)(cn={0},ou=users2,o=myorg)" will result in
  +Tomcat looking in ou=users1,o=myorg, and then ou=users2,o=myorg for the
  +username passed in from the authentication process.  You can also use
  +the standard LDAP "OR" search format, for instance
  +"(|(cn={0},o=myorg)({0}))".  Note that, as in this example, you can
  +do both context-less and fully-typed logins using this technique.</p>
   
   <p>Otherwise the realm must search the directory to find a unique entry
   containing the username. The following attributes configure this
  @@ -831,7 +839,8 @@
           directory entry, following the syntax supported by the
           <code>java.text.MessageFormat</code> class with
           <code>{0}</code> marking where the actual username should be
  -        inserted. You can use this property instead of
  +        inserted.  Multiple search locations are achieved by separating
  +        each with parentheses.  You can use this property instead of
           <code>userSearch</code>, <code>userSubtree</code> and
           <code>userBase</code> when the distinguished name contains the
           username and is otherwise the same for all users.</p>
  @@ -908,6 +917,12 @@
   objectClass: organizationalUnit
   ou: people
   
  +# Define another entry to contain admin users
  +# searches for admin users are based on this entry
  +dn: ou=admins,dc=mycompany,dc=com
  +objectClass: organizationalUnit
  +ou: admins
  +
   # Define a user entry for Janet Jones
   dn: uid=jjones,ou=people,dc=mycompany,dc=com
   objectClass: inetOrgPerson
  @@ -926,6 +941,15 @@
   mail: [EMAIL PROTECTED]
   userPassword: fred
   
  +# Define a user entry for an admin user
  +dn: uid=jsmith,ou=admins,dc=mycompany,dc=com
  +objectClass: inetOrgPerson
  +uid: jsmith
  +sn: smith
  +cn: jean smith
  +mail: [EMAIL PROTECTED]
  +userPassword: jean
  +
   # Define an entry to contain LDAP groups
   # searches for roles are based on this entry
   dn: ou=groups,dc=mycompany,dc=com
  @@ -938,6 +962,7 @@
   cn: tomcat
   uniqueMember: uid=jjones,ou=people,dc=mycompany,dc=com
   uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com
  +uniqueMember: uid=jsmith,ou=admins,dc=mycompany,dc=com
   
   # Define an entry for the "role1" role
   dn: cn=role1,ou=groups,dc=mycompany,dc=com
  @@ -967,6 +992,23 @@
   <code>userPattern</code>, authenticate by binding to the directory
   with this DN and the password received from the user, and search the
   directory to find the user's roles.</p>
  +
  +<p>If you want the realm to look in multiple pre-determined locations,
  +you can use a similar notation, surrounding each location by parentheses:</p>
  +<source>
  +&lt;Realm   className="org.apache.catalina.realm.JNDIRealm" debug="99"
  +     connectionURL="ldap://localhost:389";
  +       
userPattern="(uid={0},ou=people,dc=mycompany,dc=com)(uid={0},ou=admins,dc=mycompany,dc=com)"
  +          roleBase="ou=groups,dc=mycompany,dc=com"
  +          roleName="cn"
  +        roleSearch="(uniqueMember={0})"
  +/&gt;
  +</source>
  +<p>This pre-supposes that the User IDs in these two groups are unique;
  +the first <code>userPattern</code> that results in a valid user ID
  +will be the one used.  Note that you can support typeless logins as
  +well by adding "({0})" to the userPattern string above.  Then, Jean Smith
  +can log in as "jsmith", or "uid=jsmith,ou=admins,dc=mycompany,dc=com".</p>
   
   <p>Now suppose that users are expected to enter their email address
   rather than their userid when logging in. In this case the realm must
  
  
  
  1.15      +134 -33   
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java
  
  Index: JNDIRealm.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- JNDIRealm.java    8 Aug 2003 16:40:13 -0000       1.14
  +++ JNDIRealm.java    4 Sep 2003 19:59:47 -0000       1.15
  @@ -6,7 +6,7 @@
    * ====================================================================
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -69,8 +69,10 @@
   import java.util.ArrayList;
   import java.util.Hashtable;
   import java.util.List;
  +
   import javax.naming.Context;
   import javax.naming.CommunicationException;
  +import javax.naming.InvalidNameException;
   import javax.naming.NameNotFoundException;
   import javax.naming.NamingEnumeration;
   import javax.naming.NamingException;
  @@ -298,6 +300,17 @@
   
   
       /**
  +     * A string of LDAP user patterns or paths, ":"-separated
  +     * These will be used to form the distinguished name of a
  +     * user, with "{0}" marking the spot where the specified username
  +     * goes.
  +     * This is similar to userPattern, but allows for multiple searches
  +     * for a user.
  +     */
  +    protected String[] userPatternArray = null;
  +
  +
  +    /**
        * The message format used to form the distinguished name of a
        * user, with "{0}" marking the spot where the specified username
        * goes.
  @@ -306,10 +319,10 @@
   
   
       /**
  -     * The MessageFormat object associated with the current
  -     * <code>userPattern</code>.
  +     * An array of MessageFormat objects associated with the current
  +     * <code>userPatternArray</code>.
        */
  -    protected MessageFormat userPatternFormat = null;
  +    protected MessageFormat[] userPatternFormatArray = null;
   
   
       /**
  @@ -361,6 +374,11 @@
        */
       protected int connectionAttempt = 0;
   
  +    /**
  +     * The current user pattern to be used for lookup and binding of a user.
  +     */
  +    protected int curUserPattern = 0;
  +
       // ------------------------------------------------------------- Properties
   
       /**
  @@ -726,6 +744,11 @@
   
       /**
        * Set the message format pattern for selecting users in this Realm.
  +     * This may be one simple pattern, or multiple patterns to be tried,
  +     * separated by parentheses. (for example, either "cn={0}", or
  +     * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported,
  +     * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is
  +     * also valid. Complex search strings with &, etc are NOT supported.
        *
        * @param userPattern The new user pattern
        */
  @@ -733,12 +756,19 @@
   
           this.userPattern = userPattern;
           if (userPattern == null)
  -            userPatternFormat = null;
  -        else
  -            userPatternFormat = new MessageFormat(userPattern);
  -
  +            userPatternArray = null;
  +        else {
  +            userPatternArray = parseUserPatternString(userPattern);
  +            int len = this.userPatternArray.length;
  +            userPatternFormatArray = new MessageFormat[len];
  +            for (int i=0; i < len; i++) {
  +                userPatternFormatArray[i] =
  +                    new MessageFormat(userPatternArray[i]);
  +            }
  +        }
       }
   
  +
       /**
        * Getter for property alternateURL.
        *
  @@ -750,6 +780,7 @@
   
       }
   
  +
       /**
        * Setter for property alternateURL.
        *
  @@ -870,21 +901,50 @@
               || credentials == null || credentials.equals(""))
               return (null);
   
  -        // Retrieve user information
  -        User user = getUser(context, username);
  -        if (user == null)
  -            return (null);
  -
  -        // Check the user's credentials
  -        if (!checkCredentials(context, user, credentials))
  -            return (null);
  -
  -        // Search for additional roles
  -        List roles = getRoles(context, user);
  +        if (userPatternArray != null) {
  +            for (curUserPattern = 0;
  +                 curUserPattern < userPatternFormatArray.length;
  +                 curUserPattern++) {
  +                // Retrieve user information
  +                User user = getUser(context, username);
  +                if (user != null) {
  +                    try {
  +                        // Check the user's credentials
  +                        if (checkCredentials(context, user, credentials)) {
  +                            // Search for additional roles
  +                            List roles = getRoles(context, user);
  +                            return (new GenericPrincipal(this,
  +                                                         username,
  +                                                         credentials,
  +                                                         roles));
  +                        }
  +                    } catch (InvalidNameException ine) {
  +                        // Log the problem for posterity
  +                        log(sm.getString("jndiRealm.exception"), ine);
  +                        // ignore; this is probably due to a name not fitting
  +                        // the search path format exactly, as in a fully-
  +                        // qualified name being munged into a search path
  +                        // that already contains cn= or vice-versa
  +                    }
  +                }
  +            }
  +            return null;
  +        } else {
  +            // Retrieve user information
  +            User user = getUser(context, username);
  +            if (user == null)
  +                return (null);
  +
  +            // Check the user's credentials
  +            if (!checkCredentials(context, user, credentials))
  +                return (null);
   
  -        // Create and return a suitable Principal for this user
  -        return (new GenericPrincipal(this, username, credentials, roles));
  +            // Search for additional roles
  +            List roles = getRoles(context, user);
   
  +            // Create and return a suitable Principal for this user
  +            return (new GenericPrincipal(this, username, credentials, roles));
  +        }
       }
   
   
  @@ -919,7 +979,7 @@
           list.toArray(attrIds);
   
           // Use pattern or search for user entry
  -        if (userPatternFormat != null) {
  +        if (userPatternFormatArray != null) {
               user = getUserByPattern(context, username, attrIds);
           } else {
               user = getUserBySearch(context, username, attrIds);
  @@ -950,11 +1010,11 @@
           if (debug >= 2)
               log("lookupUser(" + username + ")");
   
  -        if (username == null || userPatternFormat == null)
  +        if (username == null || userPatternFormatArray[curUserPattern] == null)
               return (null);
   
           // Form the dn from the user pattern
  -        String dn = userPatternFormat.format(new String[] { username });
  +        String dn = userPatternFormatArray[curUserPattern].format(new String[] { 
username });
           if (debug >= 3) {
               log("  dn=" + dn);
           }
  @@ -1160,7 +1220,8 @@
                       password = password.substring(5);
                       md.reset();
                       md.update(credentials.getBytes());
  -                    String digestedPassword = new 
String(Base64.encode(md.digest()));
  +                    String digestedPassword =
  +                        new String(Base64.encode(md.digest()));
                       validated = password.equals(digestedPassword);
                   }
               } else {
  @@ -1566,7 +1627,50 @@
   
       }
   
  +    /**
  +     * Given a string containing LDAP patterns for user locations (separated by
  +     * parentheses in a pseudo-LDAP search string format -
  +     * "(location1)(location2)", returns an array of those paths.  Real LDAP
  +     * search strings are supported as well (though only the "|" "OR" type).
  +     *
  +     * @param userPatternString - a string LDAP search paths surrounded by
  +     * parentheses
  +     */
  +    protected String[] parseUserPatternString(String userPatternString) {
  +
  +        if (userPatternString != null) {
  +            ArrayList pathList = new ArrayList();
  +            int startParenLoc = userPatternString.indexOf('(');
  +            if (startParenLoc == -1) {
  +                // no parens here; return whole thing
  +                return new String[] {userPatternString};
  +            }
  +            int startingPoint = 0;
  +            while (startParenLoc > -1) {
  +                int endParenLoc = 0;
  +                // weed out escaped open parens and parens enclosing the
  +                // whole statement (in the case of valid LDAP search
  +                // strings: (|(something)(somethingelse))
  +                while ( (userPatternString.charAt(startParenLoc + 1) == '|') ||
  +                        (startParenLoc != 0 && 
userPatternString.charAt(startParenLoc - 1) == '\\') ) {
  +                    startParenLoc = userPatternString.indexOf("(", startParenLoc+1);
  +                }
  +                endParenLoc = userPatternString.indexOf(")", startParenLoc+1);
  +                // weed out escaped end-parens
  +                while (userPatternString.charAt(endParenLoc - 1) == '\\') {
  +                    endParenLoc = userPatternString.indexOf(")", endParenLoc+1);
  +                }
  +                String nextPathPart = userPatternString.substring
  +                    (startParenLoc+1, endParenLoc);
  +                pathList.add(nextPathPart);
  +                startingPoint = endParenLoc+1;
  +                startParenLoc = userPatternString.indexOf('(', startingPoint);
  +            }
  +            return (String[])pathList.toArray(new String[] {});
  +        }
  +        return null;
   
  +    }
   }
   
   // ------------------------------------------------------ Private Classes
  @@ -1581,10 +1685,7 @@
       ArrayList roles = null;
   
   
  -    User(String username,
  -             String dn,
  -             String password,
  -             ArrayList roles) {
  +    User(String username, String dn, String password, ArrayList roles) {
           this.username = username;
           this.dn = dn;
           this.password = password;
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/test/org/apache/catalina/realm/JNDIRealmTestCase.java
  
  Index: JNDIRealmTestCase.java
  ===================================================================
  /*
   * $Header: 
/home/cvspublic/jakarta-tomcat-4.0/catalina/src/test/org/apache/catalina/realm/JNDIRealmTestCase.java
   * $Revision: 1.1 $
   * $Date: 2003/09/04 19:59:47 $
   *
   * ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 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 [EMAIL PROTECTED]
   *
   * 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 junit.framework.Assert;
  import junit.framework.TestCase;
  
  /**
   * @author Jeff Tulley
   */
  public class JNDIRealmTestCase extends TestCase {
      public JNDIRealmTestCase(String arg0) {
          super(arg0);
      }
  
      public void testParseSimpleUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "o=somepath";
          String[] expected = { searchPath };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseSimpleUserPatternWithParens() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(o=somepath)";
          String[] expected = { "o=somepath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      // would somebody do this?  Probably not, but it wouldn't hurt to support it for 
resiliency sake
      public void testParseSimpleUserPatternWithParensAndLDAPOr() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(|(o=somepath))";
          String[] expected = { "o=somepath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseSimpleUserPatternWithParensPathological() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(o=so\\(me\\)path)";
          String[] expected = { "o=so\\(me\\)path" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseSimpleUserPatternWithParensReallyPathological() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(o=so\\(mepath\\))";
          String[] expected = { "o=so\\(mepath\\)" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseTwoPartUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(o=somepath)(o=someotherpath)";
          String[] expected = { "o=somepath", "o=someotherpath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      // people will probably try this, need to handle it
      public void testParseLegitLDAPTwoPartUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(|(o=somepath)(o=someotherpath))";
          String[] expected = { "o=somepath", "o=someotherpath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseTwoPartUserPatternIgnoreWhitespace() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = " (o=somepath)   (o=someotherpath)    ";
          String[] expected = { "o=somepath", "o=someotherpath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      // people will probably try this, need to handle it
      public void testParseLegitLDAPTwoPartUserPatternIgnoreWhitespace() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(| (o=somepath)         (o=someotherpath)  )";
          String[] expected = { "o=somepath", "o=someotherpath" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseTwoPartUserPatternPathological() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(o=somepath)(o=someo\\(ther\\(path)";
          String[] expected = { "o=somepath", "o=someo\\(ther\\(path" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseLegitLDAPTwoPartUserPatternPathological() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "(|(o=somepath)(o=someo\\(ther\\(path))";
          String[] expected = { "o=somepath", "o=someo\\(ther\\(path" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseMultiPartUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath =
              
"(o=somepath)(o=someotherpath)(o=somepath2)(o=someotherpath2)(o=somepath3)(o=someotherpath3)";
          String[] expected =
              {
                  "o=somepath",
                  "o=someotherpath",
                  "o=somepath2",
                  "o=someotherpath2",
                  "o=somepath3",
                  "o=someotherpath3" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseComplexMultiPartUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath =
              
"(cn={0},ou=ourou,o=somepath)(cn={0},ou=ourou,o=somepath2)(cn={0},ou=ourou,o=someotherpath2)";
          String[] expected =
              {
                  "cn={0},ou=ourou,o=somepath",
                  "cn={0},ou=ourou,o=somepath2",
                  "cn={0},ou=ourou,o=someotherpath2" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseLegitLDAPComplexMultiPartUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath =
              
"(|(cn={0},ou=ourou,o=somepath)(cn={0},ou=ourou,o=somepath2)(cn={0},ou=ourou,o=someotherpath2))";
          String[] expected =
              {
                  "cn={0},ou=ourou,o=somepath",
                  "cn={0},ou=ourou,o=somepath2",
                  "cn={0},ou=ourou,o=someotherpath2" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseComplexMultiPartUserPatternEdirectorySyntax() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath =
              
"(|(cn={0}.ou=ourou.o=somepath)(cn={0}.ou=ourou.o=somepath2)(cn={0}.ou=ourou.o=someotherpath2))";
          String[] expected =
              {
                  "cn={0}.ou=ourou.o=somepath",
                  "cn={0}.ou=ourou.o=somepath2",
                  "cn={0}.ou=ourou.o=someotherpath2" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseComplexMultiPartUserPatternTypelessEdirectorySyntax() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath =
              "(|({0}.ourou.somepath)({0}.ourou.somepath2)({0}.ourou.someotherpath2))";
          String[] expected =
              {
                  "{0}.ourou.somepath",
                  "{0}.ourou.somepath2",
                  "{0}.ourou.someotherpath2" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseEmptyUserPattern() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "";
          String[] expected = { "" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void testParseEmptyUserPatternWithParens() {
          JNDIRealm realm = new JNDIRealm();
          String searchPath = "()";
          String[] expected = { "" };
          String[] actual = realm.parseUserPatternString(searchPath);
          assertStringArraysEquals(expected, actual);
      }
  
      public void assertStringArraysEquals(String[] expected, String[] actual) {
          Assert.assertTrue("not null", actual != null);
          Assert.assertEquals("array count is wrong", expected.length, actual.length);
          for (int i = 0; i < expected.length; i++) {
              Assert.assertEquals("element " + i + " is wrong", expected[i], 
actual[i]);
          }
      }
  
      public static void main(String[] args) {
          junit.textui.TestRunner.run(JNDIRealmTestCase.class);
      }
  }
  
  
  
  
  

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

Reply via email to