You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2020/12/29 08:48:04 UTC

[tomcat] branch 8.5.x updated: 65033: Fix JNDI realm error handling

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

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


The following commit(s) were added to refs/heads/8.5.x by this push:
     new 59d9a28  65033: Fix JNDI realm error handling
59d9a28 is described below

commit 59d9a285a3101ba8f333d55c704560b08fcd8e30
Author: remm <re...@apache.org>
AuthorDate: Tue Dec 29 09:44:41 2020 +0100

    65033: Fix JNDI realm error handling
    
    Connecting to a failed server when pooling was not enabled would cause
    threads to hang in authenticate since unlocking was not done. Closing
    the connection was correctly present in that case before the refactoring
    that added pooling.
---
 java/org/apache/catalina/realm/JNDIRealm.java     | 15 ++++++++++++---
 test/org/apache/catalina/realm/TestJNDIRealm.java | 21 +++++++++++++++++++++
 webapps/docs/changelog.xml                        |  4 ++++
 3 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index daa76bf..1eedab6 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1309,10 +1309,11 @@ public class JNDIRealm extends RealmBase {
             // Ensure that we have a directory context available
             connection = get();
 
-            // Occasionally the directory context will timeout.  Try one more
-            // time before giving up.
             try {
 
+                // Occasionally the directory context will timeout.  Try one more
+                // time before giving up.
+
                 // Authenticate the specified username if possible
                 principal = authenticate(connection, username, credentials);
 
@@ -1358,6 +1359,10 @@ public class JNDIRealm extends RealmBase {
             // Log the problem for posterity
             containerLog.error(sm.getString("jndiRealm.exception"), e);
 
+            // close the connection so we know it will be reopened.
+            close(connection);
+            closePooledConnections();
+
             // Return "not authenticated" for this request
             if (containerLog.isDebugEnabled())
                 containerLog.debug("Returning null principal.");
@@ -2200,8 +2205,12 @@ public class JNDIRealm extends RealmBase {
     protected void close(JNDIConnection connection) {
 
         // Do nothing if there is no opened connection
-        if (connection.context == null)
+        if (connection == null || connection.context == null) {
+            if (connectionPool == null) {
+                singleConnectionLock.unlock();
+            }
             return;
+        }
 
         // Close tls startResponse if used
         if (tls != null) {
diff --git a/test/org/apache/catalina/realm/TestJNDIRealm.java b/test/org/apache/catalina/realm/TestJNDIRealm.java
index 5ffac18..e6fe1f5 100644
--- a/test/org/apache/catalina/realm/TestJNDIRealm.java
+++ b/test/org/apache/catalina/realm/TestJNDIRealm.java
@@ -112,6 +112,27 @@ public class TestJNDIRealm {
         Assert.assertEquals(ha1(), ((GenericPrincipal)principal).getPassword());
     }
 
+    volatile int count = 0;
+
+    @Test
+    public void testErrorRealm() throws Exception {
+        Context context = new TesterContext();
+        JNDIRealm realm = new JNDIRealm();
+        realm.setContainer(context);
+        realm.setUserSearch("");
+        // Connect to something that will fail
+        realm.setConnectionURL("ldap://127.0.0.1:12345");
+        realm.start();
+
+        count = 0;
+        (new Thread(() -> { realm.authenticate("foo", "bar"); count++; })).start();
+        (new Thread(() -> { realm.authenticate("foo", "bar"); count++; })).start();
+        (new Thread(() -> { realm.authenticate("foo", "bar"); count++; })).start();
+        Thread.sleep(10);
+
+        Assert.assertEquals(3, count);
+    }
+
 
     private JNDIRealm buildRealm(String password) throws javax.naming.NamingException,
             NoSuchFieldException, IllegalAccessException, LifecycleException {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 6755a79..0737cd0 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -149,6 +149,10 @@
         Avoid uncaught InaccessibleObjectException on Java 16 trying to clear
         references threads. (remm)
       </fix>
+      <fix>
+        <bug>65033</bug>: Fix JNDI realm error handling when connecting to a
+        failed server when pooling was not enabled. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


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