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

anmolnar 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 17e78b1da ZOOKEEPER-5043: Disable fallback to DIGEST-MD5 in SaslServer 
when FIPS mode is set
17e78b1da is described below

commit 17e78b1da0e524e1ce044e902ef178b35f4ceaf2
Author: Dávid Paksy <[email protected]>
AuthorDate: Tue May 12 17:29:11 2026 +0200

    ZOOKEEPER-5043: Disable fallback to DIGEST-MD5 in SaslServer when FIPS mode 
is set
    
    Reviewers: anmolnar
    Author: PDavid
    Closes #2384 from PDavid/ZOOKEEPER-5043-disable-DIGEST-MD5-branch-3.9
---
 .../zookeeper-client-c/tests/zkServer.sh           |  3 +-
 .../zookeeper/server/ZooKeeperSaslServer.java      | 11 +++-
 .../server/quorum/auth/SaslQuorumAuthServer.java   |  8 ++-
 .../org/apache/zookeeper/util/SecurityUtils.java   |  7 +++
 .../zookeeper/test/SaslAuthFailFipsModeTest.java   | 72 ++++++++++++++++++++++
 5 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/zookeeper-client/zookeeper-client-c/tests/zkServer.sh 
b/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
index 7505bf3a8..c7dd9bb10 100755
--- a/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
+++ b/zookeeper-client/zookeeper-client-c/tests/zkServer.sh
@@ -67,7 +67,7 @@ rm -f "${base_dir}/build/tmp/zk.pid"
 fi
 
 # [ZOOKEEPER-820] If lsof command is present, look for a process listening
-# on ZOOPORT and kill it. 
+# on ZOOPORT and kill it.
 which lsof &> /dev/null
 if [ $? -eq 0  ]
 then
@@ -129,6 +129,7 @@ if [ "x$1" == "xstartRequireSASLAuth" ]
 then
     PROPERTIES="-Dzookeeper.sessionRequireClientSASLAuth=true $PROPERTIES"
     PROPERTIES="$PROPERTIES 
-Dzookeeper.authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider"
+    PROPERTIES="$PROPERTIES -Dzookeeper.fips-mode=false"
     if [ "x$2" != "x" ]
     then
         PROPERTIES="$PROPERTIES -Djava.security.auth.login.config=$2"
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperSaslServer.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperSaslServer.java
index bf5089d79..98c8d0e6b 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperSaslServer.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperSaslServer.java
@@ -22,6 +22,7 @@
 import javax.security.sasl.SaslException;
 import javax.security.sasl.SaslServer;
 import org.apache.zookeeper.Login;
+import org.apache.zookeeper.common.ZKConfig;
 import org.apache.zookeeper.util.SecurityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,20 +33,26 @@ public class ZooKeeperSaslServer {
     public static final String DEFAULT_LOGIN_CONTEXT_NAME = "Server";
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ZooKeeperSaslServer.class);
-    private SaslServer saslServer;
+    private final SaslServer saslServer;
+    private final ZKConfig config;
 
     ZooKeeperSaslServer(final Login login) {
+        config = new ZKConfig();
         saslServer = createSaslServer(login);
     }
 
     private SaslServer createSaslServer(final Login login) {
         synchronized (login) {
             Subject subject = login.getSubject();
-            return SecurityUtils.createSaslServer(subject, "zookeeper", 
"zk-sasl-md5", login.newCallbackHandler(), LOG);
+            return SecurityUtils.createSaslServer(config, subject, 
"zookeeper", "zk-sasl-md5", login.newCallbackHandler(), LOG);
         }
     }
 
     public byte[] evaluateResponse(byte[] response) throws SaslException {
+        if (saslServer == null) {
+            LOG.error("SaslServer failed to initialize (FIPS mode may have 
blocked DIGEST-MD5). Cannot authenticate client.");
+            throw new SaslException("SaslServer is null, cannot evaluate 
client SASL response.");
+        }
         return saslServer.evaluateResponse(response);
     }
 
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthServer.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthServer.java
index a1425833b..ca651115d 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthServer.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/auth/SaslQuorumAuthServer.java
@@ -47,6 +47,7 @@ public class SaslQuorumAuthServer implements QuorumAuthServer 
{
     private static final int MAX_RETRIES = 5;
     private final Login serverLogin;
     private final boolean quorumRequireSasl;
+    private final ZKConfig zkConfig;
 
     public SaslQuorumAuthServer(boolean quorumRequireSasl, String 
loginContext, Set<String> authzHosts) throws SaslException {
         this.quorumRequireSasl = quorumRequireSasl;
@@ -60,7 +61,8 @@ public SaslQuorumAuthServer(boolean quorumRequireSasl, String 
loginContext, Set<
             Supplier<CallbackHandler> callbackSupplier = () -> {
                 return new SaslQuorumServerCallbackHandler(entries, 
authzHosts);
             };
-            serverLogin = new Login(loginContext, callbackSupplier, new 
ZKConfig());
+            zkConfig = new ZKConfig();
+            serverLogin = new Login(loginContext, callbackSupplier, zkConfig);
             serverLogin.startThreadIfNeeded();
         } catch (Throwable e) {
             throw new SaslException("Failed to initialize authentication 
mechanism using SASL", e);
@@ -86,11 +88,15 @@ public void authenticate(Socket sock, DataInputStream din) 
throws SaslException
             dout = new DataOutputStream(sock.getOutputStream());
             byte[] challenge = null;
             ss = SecurityUtils.createSaslServer(
+                zkConfig,
                 serverLogin.getSubject(),
                 QuorumAuth.QUORUM_SERVER_PROTOCOL_NAME,
                 QuorumAuth.QUORUM_SERVER_SASL_DIGEST,
                 serverLogin.newCallbackHandler(),
                 LOG);
+            if (ss == null) {
+                throw new SaslException("Failed to create SaslServer (FIPS 
mode may be blocking DIGEST-MD5)");
+            }
             while (!ss.isComplete()) {
                 challenge = ss.evaluateResponse(token);
                 if (!ss.isComplete()) {
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java
index 5c44f2116..e29dabcf0 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java
@@ -153,6 +153,7 @@ public SaslClient run() throws SaslException {
     /**
      * Create an instance of a SaslServer. It will return null if there is an 
exception.
      *
+     * @param config to check whether FIPS mode is enabled.
      * @param subject subject
      * @param protocol protocol
      * @param serverName server name
@@ -161,6 +162,7 @@ public SaslClient run() throws SaslException {
      * @return sasl server object
      */
     public static SaslServer createSaslServer(
+        final ZKConfig config,
         final Subject subject,
         final String protocol,
         final String serverName,
@@ -251,6 +253,11 @@ public SaslServer run() {
                 // JAAS non-GSSAPI authentication: assuming and supporting only
                 // DIGEST-MD5 mechanism for now.
                 // TODO: use 'authMech=' value in zoo.cfg.
+                // FIPS-mode: don't try DIGEST-MD5, just return error
+                if (X509Util.getFipsMode(config)) {
+                    LOG.warn("SaslServer will not use DIGEST-MD5 as SASL 
mechanism, because FIPS mode is enabled.");
+                    return null;
+                }
                 try {
                     SaslServer saslServer = 
Sasl.createSaslServer("DIGEST-MD5", protocol, serverName, null, 
callbackHandler);
                     return saslServer;
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailFipsModeTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailFipsModeTest.java
new file mode 100644
index 000000000..6bb09a14e
--- /dev/null
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/SaslAuthFailFipsModeTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.zookeeper.test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.common.X509Util;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that DIGEST-MD5 SASL authentication is rejected when FIPS mode is 
enabled.
+ * Does NOT extend SaslAuthDigestTestBase because that base class disables 
FIPS mode.
+ */
+public class SaslAuthFailFipsModeTest extends ClientBase {
+
+    @BeforeAll
+    public static void setUpBeforeClass() {
+        System.setProperty(X509Util.FIPS_MODE_PROPERTY, "true");
+        System.setProperty(SaslTestUtil.requireSASLAuthProperty, "true");
+        System.setProperty(SaslTestUtil.authProviderProperty, 
SaslTestUtil.authProvider);
+        System.setProperty(SaslTestUtil.jaasConfig, 
SaslTestUtil.createJAASConfigFile("jaas_fips.conf", "test"));
+    }
+
+    @AfterAll
+    public static void tearDownAfterClass() {
+        System.clearProperty(X509Util.FIPS_MODE_PROPERTY);
+        System.clearProperty(SaslTestUtil.requireSASLAuthProperty);
+        System.clearProperty(SaslTestUtil.authProviderProperty);
+        System.clearProperty(SaslTestUtil.jaasConfig);
+    }
+
+    @Test
+    public void testDigestMd5RejectedInFipsMode() throws Exception {
+        ZooKeeper zk = null;
+        CountdownWatcher watcher = new CountdownWatcher();
+        try {
+            zk = createClient(watcher);
+            zk.create("/fips-test", null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
+            fail("DIGEST-MD5 SASL authentication should be rejected when FIPS 
mode is enabled.");
+        } catch (KeeperException e) {
+            assertEquals(KeeperException.Code.AUTHFAILED, e.code());
+            
watcher.waitForDisconnected(SaslTestUtil.CLIENT_DISCONNECT_TIMEOUT);
+        } finally {
+            if (zk != null) {
+                zk.close();
+            }
+        }
+    }
+
+}

Reply via email to