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

andor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 71e173fcb ZOOKEEPER-4964. Check permissions individually during admin 
server auth
71e173fcb is described below

commit 71e173fcbcc9deb784081cf867bd045df3c32635
Author: Andor Molnar <an...@cloudera.com>
AuthorDate: Tue Aug 19 13:32:52 2025 -0500

    ZOOKEEPER-4964. Check permissions individually during admin server auth
    
    Reviewers: andor, phunt
    Author: ztzg
---
 .../apache/zookeeper/server/admin/Commands.java    | 21 +++++++++-
 .../zookeeper/server/admin/CommandAuthTest.java    | 46 +++++++++++++++++-----
 .../admin/SnapshotAndRestoreCommandTest.java       |  4 +-
 3 files changed, 59 insertions(+), 12 deletions(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java
index cd5adc76a..ae7c43691 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java
@@ -227,6 +227,18 @@ private static List<Id> handleAuthentication(final 
HttpServletRequest request, f
         }
     }
 
+    /**
+     * Grant or deny authorization for a command by matching
+     * request-provided credentials with the ACLs present on a node.
+     *
+     * @param zkServer the ZooKeeper server object.
+     * @param ids the credentials extracted from the Authorization header.
+     * @param perm the set of permission bits required by the command.
+     * @param path the ZooKeeper node path whose ACLs should be used
+     * to satisfy the perm bits.
+     * @throws KeeperException.NoAuthException if one or more perm
+     * bits could not be satisfied.
+     */
     private static void handleAuthorization(final ZooKeeperServer zkServer,
                                             final List<Id> ids,
                                             final int perm,
@@ -237,7 +249,14 @@ private static void handleAuthorization(final 
ZooKeeperServer zkServer,
             throw new KeeperException.NoNodeException(path);
         }
         final List<ACL> acls = zkServer.getZKDatabase().aclForNode(dataNode);
-        zkServer.checkACL(null, acls, perm, ids, path, null);
+        // Check the individual bits of perm.
+        final int bitWidth = Integer.SIZE - Integer.numberOfLeadingZeros(perm);
+        for (int b = 0; b < bitWidth; b++) {
+            final int permBit = 1 << b;
+            if ((perm & permBit) != 0) {
+                zkServer.checkACL(null, acls, permBit, ids, path, null);
+            }
+        }
     }
 
     /**
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java
index a6f200a10..ed5dea56c 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java
@@ -29,9 +29,11 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -185,6 +187,22 @@ public void testAuthCheck_noACL(final AuthSchema 
authSchema) throws Exception {
         assertEquals(HttpURLConnection.HTTP_OK, 
authTestConn.getResponseCode());
     }
 
+    @ParameterizedTest
+    @EnumSource(value = AuthSchema.class, names = {"DIGEST"})
+    public void testAuthCheck_noPerms(final AuthSchema authSchema) throws 
Exception {
+        // The extra ACL entry gives Perms.READ perms to the "invalid"
+        // DIGEST authInfo---but that should not permit access, as
+        // AuthTestCommand requires Perms.ADMIN.
+        setupRootACL(authSchema, ZooDefs.Ids.READ_ACL_UNSAFE);
+        try {
+            final HttpURLConnection authTestConn = 
sendAuthTestCommandRequest(authSchema, false);
+            assertEquals(HttpURLConnection.HTTP_FORBIDDEN, 
authTestConn.getResponseCode());
+        } finally {
+            addAuthInfo(zk, authSchema);
+            resetRootACL(zk);
+        }
+    }
+
     @Test
     public void testAuthCheck_invalidServerRequiredConfig() {
         assertThrows("An active server is required for auth check",
@@ -300,19 +318,29 @@ public void clearTLS() {
     }
 
     private void setupRootACL(final AuthSchema authSchema) throws Exception {
+        setupRootACL(authSchema, Collections.<ACL>emptyList());
+    }
+
+    private void setupRootACL(final AuthSchema authSchema, final List<ACL> 
extraEntries) throws Exception {
+        final List<ACL> aclEntries = new ArrayList<>();
+
         switch (authSchema) {
             case DIGEST:
-                setupRootACLForDigest(zk);
+                aclEntries.addAll(genACLForDigest());
                 break;
             case X509:
-                setupRootACLForX509(zk);
+                aclEntries.addAll(genACLForX509());
                 break;
             case IP:
-                setupRootACLForIP(zk);
+                aclEntries.addAll(genACLForIP());
                 break;
             default:
                 throw new IllegalArgumentException("Unknown auth schema");
         }
+
+        aclEntries.addAll(extraEntries);
+
+        zk.setACL(Commands.ROOT_PATH, aclEntries, -1);
     }
 
     private HttpURLConnection sendAuthTestCommandRequest(final AuthSchema 
authSchema, final boolean validAuthInfo) throws Exception  {
@@ -343,22 +371,22 @@ public static void resetRootACL(final ZooKeeper zk) 
throws Exception {
         zk.setACL(Commands.ROOT_PATH, OPEN_ACL_UNSAFE, -1);
     }
 
-    public static void setupRootACLForDigest(final ZooKeeper zk) throws 
Exception  {
+    public static List<ACL> genACLForDigest() throws Exception  {
         final String idPassword = String.format("%s:%s", ROOT_USER, 
ROOT_PASSWORD);
         final String digest = 
DigestAuthenticationProvider.generateDigest(idPassword);
 
         final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(DIGEST_SCHEMA, 
digest));
-        zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1);
+        return Collections.singletonList(acl);
     }
 
-    private static void setupRootACLForX509(final ZooKeeper zk) throws 
Exception  {
+    private static List<ACL> genACLForX509() throws Exception  {
         final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(X509_SCHEMA, 
X509_SUBJECT_PRINCIPAL));
-        zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1);
+        return Collections.singletonList(acl);
     }
 
-    private static void setupRootACLForIP(final ZooKeeper zk) throws Exception 
 {
+    private static List<ACL> genACLForIP() throws Exception  {
         final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(IP_SCHEMA, 
"127.0.0.1"));
-        zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1);
+        return Collections.singletonList(acl);
     }
 
     public static void addAuthInfoForDigest(final ZooKeeper zk) {
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/SnapshotAndRestoreCommandTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/SnapshotAndRestoreCommandTest.java
index a2f31fe86..03da02db8 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/SnapshotAndRestoreCommandTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/SnapshotAndRestoreCommandTest.java
@@ -21,7 +21,7 @@
 import static 
org.apache.zookeeper.server.ZooKeeperServer.ZOOKEEPER_SERIALIZE_LAST_PROCESSED_ZXID_ENABLED;
 import static 
org.apache.zookeeper.server.admin.CommandAuthTest.addAuthInfoForDigest;
 import static org.apache.zookeeper.server.admin.CommandAuthTest.resetRootACL;
-import static 
org.apache.zookeeper.server.admin.CommandAuthTest.setupRootACLForDigest;
+import static 
org.apache.zookeeper.server.admin.CommandAuthTest.genACLForDigest;
 import static 
org.apache.zookeeper.server.admin.Commands.ADMIN_RATE_LIMITER_INTERVAL;
 import static 
org.apache.zookeeper.server.admin.Commands.RestoreCommand.ADMIN_RESTORE_ENABLED;
 import static 
org.apache.zookeeper.server.admin.Commands.SnapshotCommand.ADMIN_SNAPSHOT_ENABLED;
@@ -119,7 +119,7 @@ public void setup() throws Exception {
         zk = ClientBase.createZKClient(hostPort);
 
         // setup root ACL
-        setupRootACLForDigest(zk);
+        zk.setACL(Commands.ROOT_PATH, genACLForDigest(), -1);
 
         // add auth
         addAuthInfoForDigest(zk);

Reply via email to