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

asf-gitbox-commits pushed a commit to branch branch-3.9
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/branch-3.9 by this push:
     new 58ab7b1d94 ZOOKEEPER-4947: Stop the send loop after SASL 
authentication fails
58ab7b1d94 is described below

commit 58ab7b1d9463ef63045335e320cbd75207a3d450
Author: Stefan Wang <[email protected]>
AuthorDate: Tue Sep 29 09:53:26 2026 -0700

    ZOOKEEPER-4947: Stop the send loop after SASL authentication fails
    
    Reviewers: kezhuw, anmolnar
    Author: 1fanwang
    Closes #2443 from 1fanwang/fix-zookeeper-4947-auth-failed-close
    
    (cherry picked from commit 92f104032d5a2f3938d6514ee46cccc07f9d522b)
    Signed-off-by: Andor Molnar <[email protected]>
---
 .../main/java/org/apache/zookeeper/ClientCnxn.java |  1 +
 .../main/java/org/apache/zookeeper/ZooKeeper.java  |  2 +-
 .../org/apache/zookeeper/TestableZooKeeper.java    |  5 ++++
 .../apache/zookeeper/test/SaslAuthFailTest.java    | 21 ++++++++++++--
 .../test/SaslAuthRequiredMultiClientTest.java      | 32 ++++++++++++++--------
 5 files changed, 46 insertions(+), 15 deletions(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
index 9e79f346de..b59d9d0a51 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
@@ -1233,6 +1233,7 @@ public void run() {
                                 eventThread.queueEvent(new 
WatchedEvent(Watcher.Event.EventType.None, authState, null));
                                 if (state == States.AUTH_FAILED) {
                                     eventThread.queueEventOfDeath();
+                                    break;
                                 }
                             }
                         }
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
index 1108833a27..18b94d97c9 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
@@ -1214,7 +1214,7 @@ public synchronized void register(Watcher watcher) {
      * @throws InterruptedException
      */
     public synchronized void close() throws InterruptedException {
-        if (!cnxn.getState().isAlive()) {
+        if (cnxn.getState() == States.CLOSED) {
             LOG.debug("Close called on already closed client");
             return;
         }
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/TestableZooKeeper.java 
b/zookeeper-server/src/test/java/org/apache/zookeeper/TestableZooKeeper.java
index 7f9e41e338..da9e5a7cc2 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/TestableZooKeeper.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/TestableZooKeeper.java
@@ -85,6 +85,11 @@ public void run() {
         }
     }
 
+    @Override
+    public boolean testableWaitForShutdown(int wait) throws 
InterruptedException {
+        return super.testableWaitForShutdown(wait);
+    }
+
     public SocketAddress testableLocalSocketAddress() {
         return super.testableLocalSocketAddress();
     }
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
index 2384cd612e..0dfd2cc955 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailTest.java
@@ -18,12 +18,18 @@
 
 package org.apache.zookeeper.test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.TestableZooKeeper;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher.Event.KeeperState;
 import org.apache.zookeeper.ZooDefs.Ids;
@@ -77,7 +83,7 @@ public synchronized void process(WatchedEvent event) {
 
     @Test
     public void testAuthFail() {
-        try (ZooKeeper zk = createClient()) {
+        try (ZooKeeper zk = new ZooKeeper(hostPort, CONNECTION_TIMEOUT, new 
CountdownWatcher())) {
             zk.create("/path1", null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
             fail("Should have gotten exception.");
         } catch (Exception e) {
@@ -88,9 +94,18 @@ public void testAuthFail() {
 
     @Test
     public void testBadSaslAuthNotifiesWatch() throws Exception {
-        try (ZooKeeper ignored = createClient(new MyWatcher(), hostPort)) {
+        try (TestableZooKeeper zk = new TestableZooKeeper(hostPort, 
CONNECTION_TIMEOUT, new MyWatcher())) {
             // wait for authFailed event from client's EventThread.
-            authFailed.await();
+            assertTrue(authFailed.await(CONNECTION_TIMEOUT, 
TimeUnit.MILLISECONDS));
+            boolean threadsStopped = zk.testableWaitForShutdown(1000);
+            LOG.info("SASL failure shutdown without close: threadsStopped={}, 
state={}",
+                     threadsStopped, zk.getState());
+            assertTrue(threadsStopped, "Client threads should stop after SASL 
authentication fails");
+            assertEquals(ZooKeeper.States.AUTH_FAILED, zk.getState());
+            assertThrows(KeeperException.AuthFailedException.class, () -> 
zk.exists("/", false));
+            zk.close();
+            assertEquals(ZooKeeper.States.CLOSED, zk.getState());
+            assertTrue(zk.close(CONNECTION_TIMEOUT));
         }
     }
 
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthRequiredMultiClientTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthRequiredMultiClientTest.java
index f21d634558..cd082f5145 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthRequiredMultiClientTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthRequiredMultiClientTest.java
@@ -19,10 +19,15 @@
 package org.apache.zookeeper.test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import javax.security.auth.login.Configuration;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
 import org.apache.zookeeper.ZooDefs.Ids;
 import org.apache.zookeeper.ZooKeeper;
 import org.junit.jupiter.api.AfterAll;
@@ -55,12 +60,7 @@ public void 
testClientOpWithInvalidSASLUserAuthAfterSuccessLogin() throws Except
         }
 
         resetJaasConfiguration("jaas.conf", "super_wrong", "test");
-        try  (ZooKeeper wrongUserZk = createClient()) {
-            wrongUserZk.create("/bar", null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
-            fail("Client with wrong SASL config should not pass SASL 
authentication.");
-        } catch (KeeperException e) {
-            assertEquals(KeeperException.Code.AUTHFAILED, e.code());
-        }
+        assertClientAuthFailed();
     }
 
     @Test
@@ -73,11 +73,21 @@ public void 
testClientOpWithInvalidSASLPasswordAuthAfterSuccessLogin() throws Ex
         }
 
         resetJaasConfiguration("jaas.conf", "super", "test_wrongong");
-        try (ZooKeeper wrongPasswordZk = createClient()) {
-            wrongPasswordZk.create("/bar", null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
-            fail("Client with wrong SASL config should not pass SASL 
authentication.");
-        } catch (KeeperException e) {
-            assertEquals(KeeperException.Code.AUTHFAILED, e.code());
+        assertClientAuthFailed();
+    }
+
+    private void assertClientAuthFailed() throws Exception {
+        CountDownLatch authFailed = new CountDownLatch(1);
+        // A rejected connection may disappear before createClient's JMX check.
+        try (ZooKeeper zk = new ZooKeeper(hostPort, CONNECTION_TIMEOUT, event 
-> {
+            if (event.getState() == KeeperState.AuthFailed) {
+                authFailed.countDown();
+            }
+        })) {
+            assertTrue(authFailed.await(CONNECTION_TIMEOUT, 
TimeUnit.MILLISECONDS));
+            assertEquals(ZooKeeper.States.AUTH_FAILED, zk.getState());
+            assertThrows(KeeperException.AuthFailedException.class,
+                         () -> zk.create("/bar", null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT));
         }
     }
 

Reply via email to