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:23:23 UTC

[tomcat] branch master updated (1db93d3 -> b201511)

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

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


    from 1db93d3  Update version number
     new fa4d19c  Start to expand JNDIRealm unit tests
     new f4d9bde  Add attribute value escaping to support user names containing ';'
     new 4e61e1d  Rename for clarity
     new d5303a5  Expand tests and fix escaping issue when searching for users by filter
     new b930d0b  Expand tests and fix an issue in escaping for group search
     new 17208c6  Expand tests and fix escaping issue in userRoleAttribute filter
     new bd4d1fb  Expanded tests to cover nested roles and fix escaping issues in search
     new 81f16b0  Expand testing to cover substitution in roleBase. Fix bugs.
     new eeb7351  Expand tests to cover escaping of substituted roleBaes values
     new b201511  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                         |  12 +
 6 files changed, 510 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit eeb7351219bd8803c0053e1e80444664a7cf5b51
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 43e9ca8..04768e8 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit fa4d19c0c6ea28eae41c29ed5b16a2ccbd7e9ba1
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                         |   8 ++
 4 files changed, 170 insertions(+)

diff --git a/build.properties.default b/build.properties.default
index fd8d153..2c3323a 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 38aeaf2..835cc36 100644
--- a/build.xml
+++ b/build.xml
@@ -3271,6 +3271,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 8e002bd..646bdab 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -104,6 +104,14 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 10.0.6 (markt)" rtext="in development">
+  <subsection name="Catalina">
+    <changelog>
+      <scode>
+        Expand coverage of unit tests for JNDIRealm using the UnboundID LDAP SDK
+        for Java. (markt)
+      </scode>
+    </changelog>
+  </subsection>
   <subsection name="Jasper">
     <changelog>
       <scode>

---------------------------------------------------------------------
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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b930d0b3161d9ec78d5fa57f886ed2de4680518b
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 ec36187..cdb9f9e 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 17208c645d68d2af1444ee8c64f36a9b8f0ba76f
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 cdb9f9e..59a56d8 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit f4d9bdef53ec009b7717620d890465fa273721a6
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 cda0603..dc10675 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);
@@ -2823,6 +2826,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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 81f16b0a7186ed02efbfac336589d6cff28d1e89
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 4f61ad6..43e9ca8 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


[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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit bd4d1fbe9146dff4714130594afd668406a6a5ef
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 59a56d8..4f61ad6 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 4e61e1d625a4a64d6b775e3a03c77a0b100d56d7
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 dc10675..c16c7b7 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()) {
@@ -2738,10 +2738,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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit d5303a506c7533803d2b3bc46e6120ce673a6667
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 c16c7b7..ec36187 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] 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 master
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b201511dfb4f74faa5ebd21248a269bbbd9b21b4
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 646bdab..e898958 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -110,6 +110,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