You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/04/13 14:26:16 UTC

[tomcat] branch 9.0.x updated (fba2bf9 -> 07d770f)

This is an automated email from the ASF dual-hosted git repository.

markt pushed a change to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git.


    from fba2bf9  Corrected instructions to reduce unit tests verbosity
     new 2a13dd8  Start to expand JNDIRealm unit tests
     new c4df8d4  Add attribute value escaping to support user names containing ';'
     new 749f3cc  Rename for clarity
     new c6b6e10  Expand tests and fix escaping issue when searching for users by filter
     new 91ecdc6  Expand tests and fix an issue in escaping for group search
     new e500674  Expand tests and fix escaping issue in userRoleAttribute filter
     new b5585a9  Expanded tests to cover nested roles and fix escaping issues in search
     new 3299320  Expand testing to cover substitution in roleBase. Fix bugs.
     new 3ce8451  Expand tests to cover escaping of substituted roleBaes values
     new 07d770f  Update changelog

The 10 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 build.properties.default                           |   9 +
 build.xml                                          |   9 +
 java/org/apache/catalina/realm/JNDIRealm.java      | 141 ++++++++++-
 .../realm/TestJNDIRealmAttributeValueEscape.java   |  86 +++++++
 .../catalina/realm/TestJNDIRealmIntegration.java   | 263 +++++++++++++++++++++
 webapps/docs/changelog.xml                         |   8 +
 6 files changed, 506 insertions(+), 10 deletions(-)
 create mode 100644 test/org/apache/catalina/realm/TestJNDIRealmAttributeValueEscape.java
 create mode 100644 test/org/apache/catalina/realm/TestJNDIRealmIntegration.java

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 03/10: Rename for clarity

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 749f3cc192c68c34f2375509aea087be45fc4434
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 11:35:07 2021 +0100

    Rename for clarity
---
 java/org/apache/catalina/realm/JNDIRealm.java | 30 +++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 1e81d89..3bba372 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1876,7 +1876,7 @@ public class JNDIRealm extends RealmBase {
         }
 
         // Set up parameters for an appropriate search
-        String filter = connection.roleFormat.format(new String[] { doRFC2254Encoding(dn), username, userRoleId });
+        String filter = connection.roleFormat.format(new String[] { doFilterEscaping(dn), username, userRoleId });
         SearchControls controls = new SearchControls();
         if (roleSubtree) {
             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
@@ -1948,7 +1948,7 @@ public class JNDIRealm extends RealmBase {
                 Map<String, String> newThisRound = new HashMap<>(); // Stores the groups we find in this iteration
 
                 for (Entry<String, String> group : newGroups.entrySet()) {
-                    filter = connection.roleFormat.format(new String[] { doRFC2254Encoding(group.getKey()),
+                    filter = connection.roleFormat.format(new String[] { doFilterEscaping(group.getKey()),
                             group.getValue(), group.getValue() });
 
                     if (containerLog.isTraceEnabled()) {
@@ -2739,10 +2739,36 @@ public class JNDIRealm extends RealmBase {
      *     )  -&gt; \29
      *     \  -&gt; \5c
      *     \0 -&gt; \00
+     *
      * @param inString string to escape according to RFC 2254 guidelines
+     *
      * @return String the escaped/encoded result
+     *
+     * @deprecated Will be removed in Tomcat 10.1.x onwards
      */
+    @Deprecated
     protected String doRFC2254Encoding(String inString) {
+        return doFilterEscaping(inString);
+    }
+
+
+    /**
+     * Given an LDAP search string, returns the string with certain characters
+     * escaped according to RFC 2254 guidelines.
+     * The character mapping is as follows:
+     *     char -&gt;  Replacement
+     *    ---------------------------
+     *     *  -&gt; \2a
+     *     (  -&gt; \28
+     *     )  -&gt; \29
+     *     \  -&gt; \5c
+     *     \0 -&gt; \00
+     *
+     * @param inString string to escape according to RFC 2254 guidelines
+     *
+     * @return String the escaped/encoded result
+     */
+    protected String doFilterEscaping(String inString) {
         StringBuilder buf = new StringBuilder(inString.length());
         for (int i = 0; i < inString.length(); i++) {
             char c = inString.charAt(i);

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 01/10: Start to expand JNDIRealm unit tests

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 2a13dd88639e92a04543585f2a9d9542e0d89f2c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 10:13:12 2021 +0100

    Start to expand JNDIRealm unit tests
---
 build.properties.default                           |   9 ++
 build.xml                                          |   9 ++
 .../catalina/realm/TestJNDIRealmIntegration.java   | 144 +++++++++++++++++++++
 webapps/docs/changelog.xml                         |   4 +
 4 files changed, 166 insertions(+)

diff --git a/build.properties.default b/build.properties.default
index 94b5663..77622d8 100644
--- a/build.properties.default
+++ b/build.properties.default
@@ -250,6 +250,15 @@ objenesis.home=${base.path}/objenesis-${objenesis.version}
 objenesis.jar=${objenesis.home}/objenesis-${objenesis.version}.jar
 objenesis.loc=${base-maven.loc}/org/objenesis/objenesis/${objenesis.version}/objenesis-${objenesis.version}.jar
 
+# ----- UnboundID, used by unit tests, version 5.1.4 or later -----
+unboundid.version=5.1.4
+unboundid.checksum.enabled=true
+unboundid.checksum.algorithm=SHA-512
+unboundid.checksum.value=04cf7f59eddebdd5b51e5be55021f9d9c667cca6101eac954e7a8d5b51f4c23372cd8f041640157f082435a166b75d85e79252b516130ede7d966dae6d3eae67
+unboundid.home=${base.path}/unboundid-${unboundid.version}
+unboundid.jar=${unboundid.home}/unboundid-ldapsdk-${unboundid.version}.jar
+unboundid.loc=${base-maven.loc}/com/unboundid/unboundid-ldapsdk/${unboundid.version}/unboundid-ldapsdk-${unboundid.version}.jar
+
 # ----- Checkstyle, version 6.16 or later -----
 checkstyle.version=8.22
 checkstyle.checksum.enabled=true
diff --git a/build.xml b/build.xml
index 15d27fb..b186186 100644
--- a/build.xml
+++ b/build.xml
@@ -3243,6 +3243,15 @@ skip.installer property in build.properties" />
       <param name="checksum.value" value="${objenesis.checksum.value}"/>
     </antcall>
 
+    <antcall target="downloadfile">
+      <param name="sourcefile" value="${unboundid.loc}"/>
+      <param name="destfile" value="${unboundid.jar}"/>
+      <param name="destdir" value="${unboundid.home}"/>
+      <param name="checksum.enabled" value="${unboundid.checksum.enabled}"/>
+      <param name="checksum.algorithm" value="${unboundid.checksum.algorithm}"/>
+      <param name="checksum.value" value="${unboundid.checksum.value}"/>
+    </antcall>
+
   </target>
 
   <target name="download-cobertura"
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
new file mode 100644
index 0000000..03e1655
--- /dev/null
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.realm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import org.apache.juli.logging.LogFactory;
+
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.sdk.AddRequest;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPResult;
+import com.unboundid.ldap.sdk.ResultCode;
+
+@RunWith(Parameterized.class)
+public class TestJNDIRealmIntegration {
+
+    private static InMemoryDirectoryServer ldapServer;
+
+    @Parameterized.Parameters(name = "{index}: in[{0}], out[{1}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        parameterSets.add(new Object[] { "test", "test", new String[] {"TestGroup"} });
+
+        return parameterSets;
+    }
+
+
+    @Parameter(0)
+    public String username;
+    @Parameter(1)
+    public String credentials;
+    @Parameter(2)
+    public String[] groups;
+
+    @Test
+    public void testAuthenication() throws Exception {
+        JNDIRealm realm = new JNDIRealm();
+        realm.containerLog = LogFactory.getLog(TestJNDIRealmIntegration.class);
+
+        realm.setConnectionURL("ldap://localhost:" + ldapServer.getListenPort());
+        realm.setUserPattern("cn={0},ou=people,dc=example,dc=com");
+        realm.setRoleName("cn");
+        realm.setRoleBase("ou=people,dc=example,dc=com");
+        realm.setRoleSearch("member={0}");
+
+        GenericPrincipal p = (GenericPrincipal) realm.authenticate(username, credentials);
+
+        Assert.assertNotNull(p);
+        Assert.assertEquals(username, p.name);
+
+        Set<String> actualGroups = new HashSet<>(Arrays.asList(p.getRoles()));
+        Set<String> expectedGroups  = new HashSet<>(Arrays.asList(groups));
+
+        Assert.assertEquals(expectedGroups.size(), actualGroups.size());
+        Set<String> tmp = new HashSet<>();
+        tmp.addAll(expectedGroups);
+        tmp.removeAll(actualGroups);
+        Assert.assertEquals(0, tmp.size());
+    }
+
+
+    @BeforeClass
+    public static void createLDAP() throws Exception {
+        InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=example,dc=com");
+        config.addAdditionalBindCredentials("cn=admin", "password");
+        ldapServer = new InMemoryDirectoryServer(config);
+
+        ldapServer.startListening();
+
+        try (LDAPConnection conn =  ldapServer.getConnection()) {
+
+            AddRequest addBase = new AddRequest(
+                    "dn: dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: domain",
+                    "dc: example");
+            LDAPResult result = conn.processOperation(addBase);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addPeople = new AddRequest(
+                    "dn: ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: organizationalUnit");
+            result = conn.processOperation(addPeople);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addUserTest = new AddRequest(
+                    "dn: cn=test,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: person",
+                    "objectClass: organizationalPerson",
+                    "cn: test",
+                    "sn: Test",
+                    "userPassword: test");
+            result = conn.processOperation(addUserTest);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addGroupTest = new AddRequest(
+                    "dn: cn=TestGroup,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: groupOfNames",
+                    "cn: TestGroup",
+                    "member: cn=test,ou=people,dc=example,dc=com");
+            result = conn.processOperation(addGroupTest);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+        }
+    }
+
+
+    @AfterClass
+    public static void destroyLDAP() {
+        ldapServer.shutDown(true);
+    }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 5a1d239..623a694 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -110,6 +110,10 @@
         Allow APR connector creation using the listener with the flag and
         the default <code>HTTP/1.1</code> protocol. (rjung/remm)
       </fix>
+      <scode>
+        Expand coverage of unit tests for JNDIRealm using the UnboundID LDAP SDK
+        for Java. (markt)
+      </scode>
     </changelog>
   </subsection>
   <subsection name="Jasper">

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 06/10: Expand tests and fix escaping issue in userRoleAttribute filter

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit e50067486cf86564175ca0cfdcbf7d209c6df862
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 12:20:06 2021 +0100

    Expand tests and fix escaping issue in userRoleAttribute filter
---
 java/org/apache/catalina/realm/JNDIRealm.java                | 6 ++++--
 test/org/apache/catalina/realm/TestJNDIRealmIntegration.java | 8 +++++---
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 0d5a78e..3e494c1 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1883,11 +1883,13 @@ public class JNDIRealm extends RealmBase {
             return list;
         }
 
-        // Set up parameters for an appropriate search
+        // Set up parameters for an appropriate search filter
+        // The dn is already attribute value escaped but the others are not
+        // This is a filter so all input will require filter escaping
         String filter = connection.roleFormat.format(new String[] {
                 doFilterEscaping(dn),
                 doFilterEscaping(doAttributeValueEscaping(username)),
-                userRoleId });
+                doFilterEscaping(doAttributeValueEscaping(userRoleId)) });
         SearchControls controls = new SearchControls();
         if (roleSubtree) {
             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index 3d9969e..8302e47 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -48,13 +48,14 @@ public class TestJNDIRealmIntegration {
     private static final String USER_BASE = "ou=people,dc=example,dc=com";
     private static final String ROLE_SEARCH_A = "member={0}";
     private static final String ROLE_SEARCH_B = "member=cn={1},ou=people,dc=example,dc=com";
+    private static final String ROLE_SEARCH_C = "member=cn={2},ou=people,dc=example,dc=com";
 
     private static InMemoryDirectoryServer ldapServer;
 
     @Parameterized.Parameters(name = "{index}: user[{3}], pwd[{4}]")
     public static Collection<Object[]> parameters() {
         List<Object[]> parameterSets = new ArrayList<>();
-        for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B }) {
+        for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B, ROLE_SEARCH_C }) {
             addUsers(USER_PATTERN, null, null, roleSearch, parameterSets);
             addUsers(null, USER_SEARCH, USER_BASE, roleSearch, parameterSets);
         }
@@ -128,6 +129,7 @@ public class TestJNDIRealmIntegration {
 
         try (LDAPConnection conn =  ldapServer.getConnection()) {
 
+            // Note: Only the DNs need attribute value escaping
             AddRequest addBase = new AddRequest(
                     "dn: dc=example,dc=com",
                     "objectClass: top",
@@ -159,7 +161,7 @@ public class TestJNDIRealmIntegration {
                     "objectClass: top",
                     "objectClass: person",
                     "objectClass: organizationalPerson",
-                    "cn: t\\;",
+                    "cn: t;",
                     "sn: Tsemicolon",
                     "userPassword: test");
             result = conn.processOperation(addUserTestSemicolon);
@@ -170,7 +172,7 @@ public class TestJNDIRealmIntegration {
                     "objectClass: top",
                     "objectClass: person",
                     "objectClass: organizationalPerson",
-                    "cn: t\\*",
+                    "cn: t*",
                     "sn: Tasterisk",
                     "userPassword: test");
             result = conn.processOperation(addUserTestAsterisk);

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 10/10: Update changelog

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 07d770fd5f8f1cc3ea3b493c96cd50baac52001b
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 15:19:37 2021 +0100

    Update changelog
---
 webapps/docs/changelog.xml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 623a694..4472321 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -114,6 +114,10 @@
         Expand coverage of unit tests for JNDIRealm using the UnboundID LDAP SDK
         for Java. (markt)
       </scode>
+      <fix>
+        <bug>65224</bug>: Ensure the correct escaping of attribute values and
+        search filters in the JNDIRealm. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 04/10: Expand tests and fix escaping issue when searching for users by filter

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c6b6e1015ae44c936971b6bf8bce70987935b92e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 11:43:51 2021 +0100

    Expand tests and fix escaping issue when searching for users by filter
---
 java/org/apache/catalina/realm/JNDIRealm.java      |  6 ++-
 .../catalina/realm/TestJNDIRealmIntegration.java   | 52 +++++++++++++++++-----
 2 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 3bba372..c0debd1 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1585,7 +1585,9 @@ public class JNDIRealm extends RealmBase {
         }
 
         // Form the search filter
-        String filter = connection.userSearchFormat.format(new String[] { username });
+        // Escape in case username contains a character with special meaning in
+        // a search filter.
+        String filter = connection.userSearchFormat.format(new String[] { doFilterEscaping(username) });
 
         // Set up the search controls
         SearchControls constraints = new SearchControls();
@@ -1753,6 +1755,8 @@ public class JNDIRealm extends RealmBase {
             return false;
         }
 
+        // This is returned from the directory so will be attribute value
+        // escaped if required
         String dn = user.getDN();
         if (dn == null) {
             return false;
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index ca45053..ef0cc35 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -43,24 +43,42 @@ import com.unboundid.ldap.sdk.ResultCode;
 @RunWith(Parameterized.class)
 public class TestJNDIRealmIntegration {
 
+    private static final String USER_PATTERN = "cn={0},ou=people,dc=example,dc=com";
+    private static final String USER_SEARCH = "cn={0}";
+    private static final String USER_BASE = "ou=people,dc=example,dc=com";
+
     private static InMemoryDirectoryServer ldapServer;
 
-    @Parameterized.Parameters(name = "{index}: in[{0}], out[{1}]")
+    @Parameterized.Parameters(name = "{index}: user[{3}], pwd[{4}]")
     public static Collection<Object[]> parameters() {
         List<Object[]> parameterSets = new ArrayList<>();
+        addUsers(USER_PATTERN, null, null, parameterSets);
+        addUsers(null, USER_SEARCH, USER_BASE, parameterSets);
+        return parameterSets;
+    }
 
-        parameterSets.add(new Object[] { "test", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { "t;", "test", new String[] {"TestGroup"} });
 
-        return parameterSets;
+    private static void addUsers(String userPattern, String userSearch, String userBase, List<Object[]> parameterSets) {
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+                "test", "test", new String[] {"TestGroup"} });
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+                "t;", "test", new String[] {"TestGroup"} });
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+                "t*", "test", new String[] {"TestGroup"} });
     }
 
 
     @Parameter(0)
-    public String username;
+    public String realmConfigUserPattern;
     @Parameter(1)
-    public String credentials;
+    public String realmConfigUserSearch;
     @Parameter(2)
+    public String realmConfigUserBase;
+    @Parameter(3)
+    public String username;
+    @Parameter(4)
+    public String credentials;
+    @Parameter(5)
     public String[] groups;
 
     @Test
@@ -69,7 +87,9 @@ public class TestJNDIRealmIntegration {
         realm.containerLog = LogFactory.getLog(TestJNDIRealmIntegration.class);
 
         realm.setConnectionURL("ldap://localhost:" + ldapServer.getListenPort());
-        realm.setUserPattern("cn={0},ou=people,dc=example,dc=com");
+        realm.setUserPattern(realmConfigUserPattern);
+        realm.setUserSearch(realmConfigUserSearch);
+        realm.setUserBase(realmConfigUserBase);
         realm.setRoleName("cn");
         realm.setRoleBase("ou=people,dc=example,dc=com");
         realm.setRoleSearch("member={0}");
@@ -131,19 +151,31 @@ public class TestJNDIRealmIntegration {
                     "objectClass: top",
                     "objectClass: person",
                     "objectClass: organizationalPerson",
-                    "cn: test",
-                    "sn: Test",
+                    "cn: t\\;",
+                    "sn: Tsemicolon",
                     "userPassword: test");
             result = conn.processOperation(addUserTestSemicolon);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
+            AddRequest addUserTestAsterisk = new AddRequest(
+                    "dn: cn=t\\*,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: person",
+                    "objectClass: organizationalPerson",
+                    "cn: t\\*",
+                    "sn: Tasterisk",
+                    "userPassword: test");
+            result = conn.processOperation(addUserTestAsterisk);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
             AddRequest addGroupTest = new AddRequest(
                     "dn: cn=TestGroup,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: groupOfNames",
                     "cn: TestGroup",
                     "member: cn=test,ou=people,dc=example,dc=com",
-                    "member: cn=t\\;,ou=people,dc=example,dc=com");
+                    "member: cn=t\\;,ou=people,dc=example,dc=com",
+                    "member: cn=t\\*,ou=people,dc=example,dc=com");
             result = conn.processOperation(addGroupTest);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
         }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 02/10: Add attribute value escaping to support user names containing '; '

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c4df8d44a959a937d507d15e5b1ca35c3dbc41eb
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 11:12:02 2021 +0100

    Add attribute value escaping to support user names containing ';'
---
 java/org/apache/catalina/realm/JNDIRealm.java      | 79 +++++++++++++++++++-
 .../realm/TestJNDIRealmAttributeValueEscape.java   | 86 ++++++++++++++++++++++
 .../catalina/realm/TestJNDIRealmIntegration.java   | 15 +++-
 3 files changed, 177 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index d94ed7f..1e81d89 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1541,8 +1541,11 @@ public class JNDIRealm extends RealmBase {
             return null;
         }
 
-        // Form the dn from the user pattern
-        String dn = connection.userPatternFormatArray[curUserPattern].format(new String[] { username });
+        // Form the DistinguishedName from the user pattern.
+        // Escape in case username contains a character with special meaning in
+        // an attribute value.
+        String dn = connection.userPatternFormatArray[curUserPattern].format(
+                new String[] { doAttributeValueEscaping(username) });
 
         try {
             user = getUserByPattern(connection.context, username, attrIds, dn);
@@ -2824,6 +2827,78 @@ public class JNDIRealm extends RealmBase {
     }
 
 
+    /**
+     * Implements the necessary escaping to represent an attribute value as a
+     * String as per RFC 4514.
+     *
+     * @param input The original attribute value
+     * @return      The string representation of the attribute value
+     */
+    protected String doAttributeValueEscaping(String input) {
+        int len = input.length();
+        StringBuilder result = new StringBuilder();
+
+        for (int i = 0; i < len; i++) {
+            char c = input.charAt(i);
+            switch (c) {
+                case ' ': {
+                    if (i == 0 || i == (len -1)) {
+                        result.append("\\20");
+                    } else {
+                        result.append(c);
+                    }
+                    break;
+                }
+                case '#': {
+                    if (i == 0 ) {
+                        result.append("\\23");
+                    } else {
+                        result.append(c);
+                    }
+                    break;
+                }
+                case '\"': {
+                    result.append("\\22");
+                    break;
+                }
+                case '+': {
+                    result.append("\\2B");
+                    break;
+                }
+                case ',': {
+                    result.append("\\2C");
+                    break;
+                }
+                case ';': {
+                    result.append("\\3B");
+                    break;
+                }
+                case '<': {
+                    result.append("\\3C");
+                    break;
+                }
+                case '>': {
+                    result.append("\\3E");
+                    break;
+                }
+                case '\\': {
+                    result.append("\\5C");
+                    break;
+                }
+                case '\u0000': {
+                    result.append("\\00");
+                    break;
+                }
+                default:
+                    result.append(c);
+            }
+
+        }
+
+        return result.toString();
+    }
+
+
     protected static String convertToHexEscape(String input) {
         if (input.indexOf('\\') == -1) {
             // No escaping present. Return original.
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmAttributeValueEscape.java b/test/org/apache/catalina/realm/TestJNDIRealmAttributeValueEscape.java
new file mode 100644
index 0000000..677bcc5
--- /dev/null
+++ b/test/org/apache/catalina/realm/TestJNDIRealmAttributeValueEscape.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.realm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+@RunWith(Parameterized.class)
+public class TestJNDIRealmAttributeValueEscape {
+
+    @Parameterized.Parameters(name = "{index}: in[{0}], out[{1}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        // No escaping required
+        parameterSets.add(new String[] { "none", "none" });
+        // Simple cases (same order as RFC 4512 section 2)
+        // Each appearing at the beginning, middle and ent
+        parameterSets.add(new String[] { " test", "\\20test" });
+        parameterSets.add(new String[] { "te st", "te st" });
+        parameterSets.add(new String[] { "test ", "test\\20" });
+        parameterSets.add(new String[] { "#test", "\\23test" });
+        parameterSets.add(new String[] { "te#st", "te#st" });
+        parameterSets.add(new String[] { "test#", "test#" });
+        parameterSets.add(new String[] { "\"test", "\\22test" });
+        parameterSets.add(new String[] { "te\"st", "te\\22st" });
+        parameterSets.add(new String[] { "test\"", "test\\22" });
+        parameterSets.add(new String[] { "+test", "\\2Btest" });
+        parameterSets.add(new String[] { "te+st", "te\\2Bst" });
+        parameterSets.add(new String[] { "test+", "test\\2B" });
+        parameterSets.add(new String[] { ",test", "\\2Ctest" });
+        parameterSets.add(new String[] { "te,st", "te\\2Cst" });
+        parameterSets.add(new String[] { "test,", "test\\2C" });
+        parameterSets.add(new String[] { ";test", "\\3Btest" });
+        parameterSets.add(new String[] { "te;st", "te\\3Bst" });
+        parameterSets.add(new String[] { "test;", "test\\3B" });
+        parameterSets.add(new String[] { "<test", "\\3Ctest" });
+        parameterSets.add(new String[] { "te<st", "te\\3Cst" });
+        parameterSets.add(new String[] { "test<", "test\\3C" });
+        parameterSets.add(new String[] { ">test", "\\3Etest" });
+        parameterSets.add(new String[] { "te>st", "te\\3Est" });
+        parameterSets.add(new String[] { "test>", "test\\3E" });
+        parameterSets.add(new String[] { "\\test", "\\5Ctest" });
+        parameterSets.add(new String[] { "te\\st", "te\\5Cst" });
+        parameterSets.add(new String[] { "test\\", "test\\5C" });
+        parameterSets.add(new String[] { "\u0000test", "\\00test" });
+        parameterSets.add(new String[] { "te\u0000st", "te\\00st" });
+        parameterSets.add(new String[] { "test\u0000", "test\\00" });
+        return parameterSets;
+    }
+
+
+    @Parameter(0)
+    public String in;
+    @Parameter(1)
+    public String out;
+
+    private JNDIRealm realm = new JNDIRealm();
+
+    @Test
+    public void testConvertToHexEscape() throws Exception {
+        String result = realm.doAttributeValueEscaping(in);
+        Assert.assertEquals(out, result);
+    }
+}
\ No newline at end of file
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index 03e1655..ca45053 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -50,6 +50,7 @@ public class TestJNDIRealmIntegration {
         List<Object[]> parameterSets = new ArrayList<>();
 
         parameterSets.add(new Object[] { "test", "test", new String[] {"TestGroup"} });
+        parameterSets.add(new Object[] { "t;", "test", new String[] {"TestGroup"} });
 
         return parameterSets;
     }
@@ -125,12 +126,24 @@ public class TestJNDIRealmIntegration {
             result = conn.processOperation(addUserTest);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
+            AddRequest addUserTestSemicolon = new AddRequest(
+                    "dn: cn=t\\;,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: person",
+                    "objectClass: organizationalPerson",
+                    "cn: test",
+                    "sn: Test",
+                    "userPassword: test");
+            result = conn.processOperation(addUserTestSemicolon);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
             AddRequest addGroupTest = new AddRequest(
                     "dn: cn=TestGroup,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: groupOfNames",
                     "cn: TestGroup",
-                    "member: cn=test,ou=people,dc=example,dc=com");
+                    "member: cn=test,ou=people,dc=example,dc=com",
+                    "member: cn=t\\;,ou=people,dc=example,dc=com");
             result = conn.processOperation(addGroupTest);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
         }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 07/10: Expanded tests to cover nested roles and fix escaping issues in search

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b5585a9e5d4fec020cc5ebadb82f899fae22bc43
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 12:54:24 2021 +0100

    Expanded tests to cover nested roles and fix escaping issues in search
---
 java/org/apache/catalina/realm/JNDIRealm.java      |  9 ++++--
 .../catalina/realm/TestJNDIRealmIntegration.java   | 34 +++++++++++++++++++++-
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 3e494c1..1c11f8c 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1961,8 +1961,13 @@ public class JNDIRealm extends RealmBase {
                 Map<String, String> newThisRound = new HashMap<>(); // Stores the groups we find in this iteration
 
                 for (Entry<String, String> group : newGroups.entrySet()) {
-                    filter = connection.roleFormat.format(new String[] { doFilterEscaping(group.getKey()),
-                            group.getValue(), group.getValue() });
+                    // Group key is already value escaped if required
+                    // Group value is not value escaped
+                    // Everything needs to be filter escaped
+                    filter = connection.roleFormat.format(new String[] {
+                            doFilterEscaping(group.getKey()),
+                            doFilterEscaping(doAttributeValueEscaping(group.getValue())),
+                            doFilterEscaping(doAttributeValueEscaping(group.getValue())) });
 
                     if (containerLog.isTraceEnabled()) {
                         containerLog.trace("Perform a nested group search with base "+ roleBase +
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index 8302e47..cf47369 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -52,7 +52,7 @@ public class TestJNDIRealmIntegration {
 
     private static InMemoryDirectoryServer ldapServer;
 
-    @Parameterized.Parameters(name = "{index}: user[{3}], pwd[{4}]")
+    @Parameterized.Parameters(name = "{index}: user[{4}], pwd[{5}]")
     public static Collection<Object[]> parameters() {
         List<Object[]> parameterSets = new ArrayList<>();
         for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B, ROLE_SEARCH_C }) {
@@ -71,6 +71,8 @@ public class TestJNDIRealmIntegration {
                 "t;", "test", new String[] {"TestGroup"} });
         parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
                 "t*", "test", new String[] {"TestGroup"} });
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
+                "t=", "test", new String[] {"Test<Group*2", "Test>Group*3"} });
     }
 
 
@@ -102,6 +104,7 @@ public class TestJNDIRealmIntegration {
         realm.setRoleName("cn");
         realm.setRoleBase("ou=people,dc=example,dc=com");
         realm.setRoleSearch(realmConfigRoleSearch);
+        realm.setRoleNested(true);
 
         GenericPrincipal p = (GenericPrincipal) realm.authenticate(username, credentials);
 
@@ -178,6 +181,17 @@ public class TestJNDIRealmIntegration {
             result = conn.processOperation(addUserTestAsterisk);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
+            AddRequest addUserTestEquals = new AddRequest(
+                    "dn: cn=t\\=,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: person",
+                    "objectClass: organizationalPerson",
+                    "cn: t=",
+                    "sn: Tequals",
+                    "userPassword: test");
+            result = conn.processOperation(addUserTestEquals);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
             AddRequest addGroupTest = new AddRequest(
                     "dn: cn=TestGroup,ou=people,dc=example,dc=com",
                     "objectClass: top",
@@ -188,6 +202,24 @@ public class TestJNDIRealmIntegration {
                     "member: cn=t\\*,ou=people,dc=example,dc=com");
             result = conn.processOperation(addGroupTest);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addGroupTest2 = new AddRequest(
+                    "dn: cn=Test\\<Group*2,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: groupOfNames",
+                    "cn: Test<Group*2",
+                    "member: cn=t\\=,ou=people,dc=example,dc=com");
+            result = conn.processOperation(addGroupTest2);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addGroupTest3 = new AddRequest(
+                    "dn: cn=Test\\>Group*3,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: groupOfNames",
+                    "cn: Test>Group*3",
+                    "member: cn=Test\\<Group*2,ou=people,dc=example,dc=com");
+            result = conn.processOperation(addGroupTest3);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
         }
     }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 05/10: Expand tests and fix an issue in escaping for group search

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 91ecdc61ce3420054c04114baaaf1c1e0cbd5d56
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 12:11:35 2021 +0100

    Expand tests and fix an issue in escaping for group search
---
 java/org/apache/catalina/realm/JNDIRealm.java      |  9 +++++++-
 .../catalina/realm/TestJNDIRealmIntegration.java   | 26 ++++++++++++++--------
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index c0debd1..0d5a78e 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1847,7 +1847,11 @@ public class JNDIRealm extends RealmBase {
             return null;
         }
 
+        // This is returned from the directory so will be attribute value
+        // escaped if required
         String dn = user.getDN();
+        // This is the name the user provided to the authentication process so
+        // it will not be escaped
         String username = user.getUserName();
         String userRoleId = user.getUserRoleId();
 
@@ -1880,7 +1884,10 @@ public class JNDIRealm extends RealmBase {
         }
 
         // Set up parameters for an appropriate search
-        String filter = connection.roleFormat.format(new String[] { doFilterEscaping(dn), username, userRoleId });
+        String filter = connection.roleFormat.format(new String[] {
+                doFilterEscaping(dn),
+                doFilterEscaping(doAttributeValueEscaping(username)),
+                userRoleId });
         SearchControls controls = new SearchControls();
         if (roleSubtree) {
             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index ef0cc35..3d9969e 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -46,24 +46,29 @@ public class TestJNDIRealmIntegration {
     private static final String USER_PATTERN = "cn={0},ou=people,dc=example,dc=com";
     private static final String USER_SEARCH = "cn={0}";
     private static final String USER_BASE = "ou=people,dc=example,dc=com";
+    private static final String ROLE_SEARCH_A = "member={0}";
+    private static final String ROLE_SEARCH_B = "member=cn={1},ou=people,dc=example,dc=com";
 
     private static InMemoryDirectoryServer ldapServer;
 
     @Parameterized.Parameters(name = "{index}: user[{3}], pwd[{4}]")
     public static Collection<Object[]> parameters() {
         List<Object[]> parameterSets = new ArrayList<>();
-        addUsers(USER_PATTERN, null, null, parameterSets);
-        addUsers(null, USER_SEARCH, USER_BASE, parameterSets);
+        for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B }) {
+            addUsers(USER_PATTERN, null, null, roleSearch, parameterSets);
+            addUsers(null, USER_SEARCH, USER_BASE, roleSearch, parameterSets);
+        }
         return parameterSets;
     }
 
 
-    private static void addUsers(String userPattern, String userSearch, String userBase, List<Object[]> parameterSets) {
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+    private static void addUsers(String userPattern, String userSearch, String userBase, String roleSearch,
+            List<Object[]> parameterSets) {
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
                 "test", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
                 "t;", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase,
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
                 "t*", "test", new String[] {"TestGroup"} });
     }
 
@@ -75,10 +80,12 @@ public class TestJNDIRealmIntegration {
     @Parameter(2)
     public String realmConfigUserBase;
     @Parameter(3)
-    public String username;
+    public String realmConfigRoleSearch;
     @Parameter(4)
-    public String credentials;
+    public String username;
     @Parameter(5)
+    public String credentials;
+    @Parameter(6)
     public String[] groups;
 
     @Test
@@ -90,9 +97,10 @@ public class TestJNDIRealmIntegration {
         realm.setUserPattern(realmConfigUserPattern);
         realm.setUserSearch(realmConfigUserSearch);
         realm.setUserBase(realmConfigUserBase);
+        realm.setUserRoleAttribute("cn");
         realm.setRoleName("cn");
         realm.setRoleBase("ou=people,dc=example,dc=com");
-        realm.setRoleSearch("member={0}");
+        realm.setRoleSearch(realmConfigRoleSearch);
 
         GenericPrincipal p = (GenericPrincipal) realm.authenticate(username, credentials);
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 09/10: Expand tests to cover escaping of substituted roleBaes values

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 3ce84512ed8783577d9945df28da5a033465b945
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 15:19:31 2021 +0100

    Expand tests to cover escaping of substituted roleBaes values
    
    While the UnboundedID LDAP SDK doesn't appear to have a preference some
    servers (Windows AD, OpenLDAP) do appear to.
---
 java/org/apache/catalina/realm/JNDIRealm.java                |  4 +++-
 test/org/apache/catalina/realm/TestJNDIRealmIntegration.java | 10 +++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 908d8ae..5648201 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1904,7 +1904,9 @@ public class JNDIRealm extends RealmBase {
             Name name = np.parse(dn);
             String nameParts[] = new String[name.size()];
             for (int i = 0; i < name.size(); i++) {
-                nameParts[i] = name.get(i);
+                // May have been returned with \<char> escaping rather than
+                // \<hex><hex>. Make sure it is \<hex><hex>.
+                nameParts[i] =  convertToHexEscape(name.get(i));
             }
             base = connection.roleBaseFormat.format(nameParts);
         } else {
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index d019fc0..cd69267 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -60,7 +60,7 @@ public class TestJNDIRealmIntegration {
             addUsers(USER_PATTERN, null, null, roleSearch, ROLE_BASE, parameterSets);
             addUsers(null, USER_SEARCH, USER_BASE, roleSearch, ROLE_BASE, parameterSets);
         }
-        parameterSets.add(new Object[] { "cn={0},ou=sub,ou=people,dc=example,dc=com", null, null, ROLE_SEARCH_A,
+        parameterSets.add(new Object[] { "cn={0},ou=s\\;ub,ou=people,dc=example,dc=com", null, null, ROLE_SEARCH_A,
                 "{3},ou=people,dc=example,dc=com", "testsub", "test", new String[] {"TestGroup4"} });
         return parameterSets;
     }
@@ -227,14 +227,14 @@ public class TestJNDIRealmIntegration {
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
             AddRequest addPeopleSub = new AddRequest(
-                    "dn: ou=sub,ou=people,dc=example,dc=com",
+                    "dn: ou=s\\;ub,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: organizationalUnit");
             result = conn.processOperation(addPeopleSub);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
             AddRequest addUserTestSub = new AddRequest(
-                    "dn: cn=testsub,ou=sub,ou=people,dc=example,dc=com",
+                    "dn: cn=testsub,ou=s\\;ub,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: person",
                     "objectClass: organizationalPerson",
@@ -245,11 +245,11 @@ public class TestJNDIRealmIntegration {
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
             AddRequest addGroupTest4 = new AddRequest(
-                    "dn: cn=TestGroup4,ou=sub,ou=people,dc=example,dc=com",
+                    "dn: cn=TestGroup4,ou=s\\;ub,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: groupOfNames",
                     "cn: TestGroup4",
-                    "member: cn=testsub,ou=sub,ou=people,dc=example,dc=com");
+                    "member: cn=testsub,ou=s\\;ub,ou=people,dc=example,dc=com");
             result = conn.processOperation(addGroupTest4);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
         }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 08/10: Expand testing to cover substitution in roleBase. Fix bugs.

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 329932012d3a9b95fde0b18618416e659ecffdc0
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Apr 13 14:47:07 2021 +0100

    Expand testing to cover substitution in roleBase. Fix bugs.
    
    The code incorrectly referred to the original roleBase rather than the
    local version that includes the substituted value(s).
---
 java/org/apache/catalina/realm/JNDIRealm.java      |  4 +-
 .../catalina/realm/TestJNDIRealmIntegration.java   | 56 +++++++++++++++++-----
 2 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 1c11f8c..908d8ae 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1927,7 +1927,7 @@ public class JNDIRealm extends RealmBase {
                 if (attrs == null) {
                     continue;
                 }
-                String dname = getDistinguishedName(connection.context, roleBase, result);
+                String dname = getDistinguishedName(connection.context, base, result);
                 String name = getAttributeValue(roleName, attrs);
                 if (name != null && dname != null) {
                     groupMap.put(dname, name);
@@ -1974,7 +1974,7 @@ public class JNDIRealm extends RealmBase {
                                 " and filter " + filter);
                     }
 
-                    results = searchAsUser(connection.context, user, roleBase, filter, controls, isRoleSearchAsUser());
+                    results = searchAsUser(connection.context, user, base, filter, controls, isRoleSearchAsUser());
 
                     try {
                         while (results.hasMore()) {
diff --git a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
index cf47369..d019fc0 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealmIntegration.java
@@ -49,29 +49,32 @@ public class TestJNDIRealmIntegration {
     private static final String ROLE_SEARCH_A = "member={0}";
     private static final String ROLE_SEARCH_B = "member=cn={1},ou=people,dc=example,dc=com";
     private static final String ROLE_SEARCH_C = "member=cn={2},ou=people,dc=example,dc=com";
+    private static final String ROLE_BASE = "ou=people,dc=example,dc=com";
 
     private static InMemoryDirectoryServer ldapServer;
 
-    @Parameterized.Parameters(name = "{index}: user[{4}], pwd[{5}]")
+    @Parameterized.Parameters(name = "{index}: user[{5}], pwd[{6}]")
     public static Collection<Object[]> parameters() {
         List<Object[]> parameterSets = new ArrayList<>();
         for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B, ROLE_SEARCH_C }) {
-            addUsers(USER_PATTERN, null, null, roleSearch, parameterSets);
-            addUsers(null, USER_SEARCH, USER_BASE, roleSearch, parameterSets);
+            addUsers(USER_PATTERN, null, null, roleSearch, ROLE_BASE, parameterSets);
+            addUsers(null, USER_SEARCH, USER_BASE, roleSearch, ROLE_BASE, parameterSets);
         }
+        parameterSets.add(new Object[] { "cn={0},ou=sub,ou=people,dc=example,dc=com", null, null, ROLE_SEARCH_A,
+                "{3},ou=people,dc=example,dc=com", "testsub", "test", new String[] {"TestGroup4"} });
         return parameterSets;
     }
 
 
     private static void addUsers(String userPattern, String userSearch, String userBase, String roleSearch,
-            List<Object[]> parameterSets) {
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
+            String roleBase, List<Object[]> parameterSets) {
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
                 "test", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
                 "t;", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
                 "t*", "test", new String[] {"TestGroup"} });
-        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch,
+        parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
                 "t=", "test", new String[] {"Test<Group*2", "Test>Group*3"} });
     }
 
@@ -85,10 +88,12 @@ public class TestJNDIRealmIntegration {
     @Parameter(3)
     public String realmConfigRoleSearch;
     @Parameter(4)
-    public String username;
+    public String realmConfigRoleBase;
     @Parameter(5)
-    public String credentials;
+    public String username;
     @Parameter(6)
+    public String credentials;
+    @Parameter(7)
     public String[] groups;
 
     @Test
@@ -102,7 +107,7 @@ public class TestJNDIRealmIntegration {
         realm.setUserBase(realmConfigUserBase);
         realm.setUserRoleAttribute("cn");
         realm.setRoleName("cn");
-        realm.setRoleBase("ou=people,dc=example,dc=com");
+        realm.setRoleBase(realmConfigRoleBase);
         realm.setRoleSearch(realmConfigRoleSearch);
         realm.setRoleNested(true);
 
@@ -171,7 +176,7 @@ public class TestJNDIRealmIntegration {
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
 
             AddRequest addUserTestAsterisk = new AddRequest(
-                    "dn: cn=t\\*,ou=people,dc=example,dc=com",
+                    "dn: cn=t*,ou=people,dc=example,dc=com",
                     "objectClass: top",
                     "objectClass: person",
                     "objectClass: organizationalPerson",
@@ -220,6 +225,33 @@ public class TestJNDIRealmIntegration {
                     "member: cn=Test\\<Group*2,ou=people,dc=example,dc=com");
             result = conn.processOperation(addGroupTest3);
             Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addPeopleSub = new AddRequest(
+                    "dn: ou=sub,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: organizationalUnit");
+            result = conn.processOperation(addPeopleSub);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addUserTestSub = new AddRequest(
+                    "dn: cn=testsub,ou=sub,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: person",
+                    "objectClass: organizationalPerson",
+                    "cn: testsub",
+                    "sn: Testsub",
+                    "userPassword: test");
+            result = conn.processOperation(addUserTestSub);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
+
+            AddRequest addGroupTest4 = new AddRequest(
+                    "dn: cn=TestGroup4,ou=sub,ou=people,dc=example,dc=com",
+                    "objectClass: top",
+                    "objectClass: groupOfNames",
+                    "cn: TestGroup4",
+                    "member: cn=testsub,ou=sub,ou=people,dc=example,dc=com");
+            result = conn.processOperation(addGroupTest4);
+            Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
         }
     }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org