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:45:24 UTC

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


The following commit(s) were added to refs/heads/master by this push:
     new 55f2f35  65033: Fix JNDI realm error handling
55f2f35 is described below

commit 55f2f355c778dae68a4a154cc6eaf10e997872c9
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 e7543d8..7e09d5c 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -1301,10 +1301,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);
 
@@ -1350,6 +1351,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.");
@@ -2192,8 +2197,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 845bc61..8bc2a01 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(USER, principal.getName());
     }
 
+    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 7576672..2373340 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -142,6 +142,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