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

mdrob pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 2e4ddc7  SOLR-15249 Attempt to repair security.json ACLs
2e4ddc7 is described below

commit 2e4ddc7b9852124db63c0e5ab043dfc6445cac55
Author: Mike Drob <[email protected]>
AuthorDate: Mon Apr 5 17:31:00 2021 -0500

    SOLR-15249 Attempt to repair security.json ACLs
---
 .../java/org/apache/solr/cloud/ZkController.java   | 37 ++++++++++++++++++++--
 .../VMParamsZkACLAndCredentialsProvidersTest.java  | 30 +++++++++++++++++-
 .../common/cloud/SecurityAwareZkACLProvider.java   |  2 +-
 3 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java 
b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
index 9c92892..c0cf7f0 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -92,6 +92,7 @@ import 
org.apache.zookeeper.KeeperException.SessionExpiredException;
 import org.apache.zookeeper.Op;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -856,9 +857,39 @@ public class ZkController implements Closeable {
     cmdExecutor.ensureExists(ZkStateReader.ALIASES, zkClient);
     byte[] emptyJson = "{}".getBytes(StandardCharsets.UTF_8);
     cmdExecutor.ensureExists(ZkStateReader.SOLR_SECURITY_CONF_PATH, emptyJson, 
zkClient);
-    if (zkClient.getACL(ZkStateReader.SOLR_SECURITY_CONF_PATH, null, 
true).equals(OPEN_ACL_UNSAFE)) {
-      log.warn("Contents of zookeeper /security.json are world-readable;" +
-              " consider setting up ACLs as described in 
https://solr.apache.org/guide/zookeeper-access-control.html";);
+    repairSecurityJson(zkClient);
+  }
+
+  private static void repairSecurityJson(SolrZkClient zkClient) throws 
KeeperException, InterruptedException {
+    List<ACL> securityConfAcl = 
zkClient.getACL(ZkStateReader.SOLR_SECURITY_CONF_PATH, null, true);
+    ZkACLProvider aclProvider = zkClient.getZkACLProvider();
+
+    boolean tryUpdate = false;
+
+    if (OPEN_ACL_UNSAFE.equals(securityConfAcl)) {
+      List<ACL> aclToAdd = 
aclProvider.getACLsToAdd(ZkStateReader.SOLR_SECURITY_CONF_PATH);
+      if (OPEN_ACL_UNSAFE.equals(aclToAdd)) {
+        log.warn("Contents of zookeeper /security.json are world-readable;" +
+            " consider setting up ACLs as described in 
https://solr.apache.org/guide/zookeeper-access-control.html";);
+      } else {
+        tryUpdate = true;
+      }
+    } else if (aclProvider instanceof SecurityAwareZkACLProvider) {
+      // Use Set to explicitly ignore order
+      Set<ACL> nonSecureACL = new HashSet<>(aclProvider.getACLsToAdd(null));
+      // case where security.json was not treated as a secure path
+      if (nonSecureACL.equals(new HashSet<>(securityConfAcl))) {
+        tryUpdate = true;
+      }
+    }
+
+    if (tryUpdate) {
+      if (Boolean.getBoolean("solr.security.aclautorepair.disable")) {
+        log.warn("Detected inconsistent ACLs for zookeeper /security.json, but 
self-repair is disabled.");
+      } else {
+        log.info("Detected inconsistent ACLs for zookeeper /security.json, 
attempting to repair.");
+        zkClient.updateACLs(ZkStateReader.SOLR_SECURITY_CONF_PATH);
+      }
     }
   }
 
diff --git 
a/solr/core/src/test/org/apache/solr/cloud/VMParamsZkACLAndCredentialsProvidersTest.java
 
b/solr/core/src/test/org/apache/solr/cloud/VMParamsZkACLAndCredentialsProvidersTest.java
index a8a3c74..47408ab 100644
--- 
a/solr/core/src/test/org/apache/solr/cloud/VMParamsZkACLAndCredentialsProvidersTest.java
+++ 
b/solr/core/src/test/org/apache/solr/cloud/VMParamsZkACLAndCredentialsProvidersTest.java
@@ -34,6 +34,8 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.zookeeper.ZooDefs.Ids.OPEN_ACL_UNSAFE;
+
 public class VMParamsZkACLAndCredentialsProvidersTest extends SolrTestCaseJ4 {
   
   private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -151,6 +153,32 @@ public class VMParamsZkACLAndCredentialsProvidersTest 
extends SolrTestCaseJ4 {
               false, false, false, false, false);
     }
   }
+
+  @Test
+  public void testRepairACL() throws Exception {
+    clearSecuritySystemProperties();
+    try (SolrZkClient zkClient = new SolrZkClient(zkServer.getZkAddress(), 
AbstractZkTestCase.TIMEOUT)) {
+      // Currently no credentials on ZK connection, because those same 
VM-params are used for adding ACLs, and here we want
+      // no (or completely open) ACLs added. Therefore hack your way into 
being authorized for creating anyway
+      zkClient.getSolrZooKeeper().addAuthInfo("digest", 
("connectAndAllACLUsername:connectAndAllACLPassword")
+          .getBytes(StandardCharsets.UTF_8));
+
+      zkClient.create("/security.json", "{}".getBytes(StandardCharsets.UTF_8), 
CreateMode.PERSISTENT, false);
+      assertEquals(OPEN_ACL_UNSAFE, zkClient.getACL("/security.json", null, 
false));
+    }
+
+    setSecuritySystemProperties();
+    try (SolrZkClient zkClient = new SolrZkClient(zkServer.getZkAddress(), 
AbstractZkTestCase.TIMEOUT)) {
+      ZkController.createClusterZkNodes(zkClient);
+      assertNotEquals(OPEN_ACL_UNSAFE, zkClient.getACL("/security.json", null, 
false));
+    }
+
+    useReadonlyCredentials();
+    try (SolrZkClient zkClient = new SolrZkClient(zkServer.getZkAddress(), 
AbstractZkTestCase.TIMEOUT)) {
+      NoAuthException e = assertThrows(NoAuthException.class, () -> 
zkClient.getData("/security.json", null, null, false));
+      assertEquals("/security.json", e.getPath());
+    }
+  }
     
   protected static void doTest(
       SolrZkClient zkClient,
@@ -202,7 +230,7 @@ public class VMParamsZkACLAndCredentialsProvidersTest 
extends SolrTestCaseJ4 {
   private void useWrongCredentials() {
     clearSecuritySystemProperties();
     
-    System.setProperty(SolrZkClient.ZK_ACL_PROVIDER_CLASS_NAME_VM_PARAM_NAME, 
VMParamsSingleSetCredentialsDigestZkCredentialsProvider.class.getName());
+    System.setProperty(SolrZkClient.ZK_CRED_PROVIDER_CLASS_NAME_VM_PARAM_NAME, 
VMParamsSingleSetCredentialsDigestZkCredentialsProvider.class.getName());
     
System.setProperty(VMParamsSingleSetCredentialsDigestZkCredentialsProvider.DEFAULT_DIGEST_USERNAME_VM_PARAM_NAME,
 "connectAndAllACLUsername");
     
System.setProperty(VMParamsSingleSetCredentialsDigestZkCredentialsProvider.DEFAULT_DIGEST_PASSWORD_VM_PARAM_NAME,
 "connectAndAllACLPasswordWrong");
   }
diff --git 
a/solr/solrj/src/java/org/apache/solr/common/cloud/SecurityAwareZkACLProvider.java
 
b/solr/solrj/src/java/org/apache/solr/common/cloud/SecurityAwareZkACLProvider.java
index 2fe2da9..300c649 100644
--- 
a/solr/solrj/src/java/org/apache/solr/common/cloud/SecurityAwareZkACLProvider.java
+++ 
b/solr/solrj/src/java/org/apache/solr/common/cloud/SecurityAwareZkACLProvider.java
@@ -33,7 +33,7 @@ public abstract class SecurityAwareZkACLProvider implements 
ZkACLProvider {
 
 
   @Override
-  public List<ACL> getACLsToAdd(String zNodePath) {
+  public final List<ACL> getACLsToAdd(String zNodePath) {
     if (isSecurityZNodePath(zNodePath)) {
       return getSecurityACLsToAdd();
     } else {

Reply via email to