You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ep...@apache.org on 2023/09/12 18:45:04 UTC

[solr] branch branch_9x updated: SOLR-15771: bin/solr auth enable should model best practices for security.json (#1851)

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

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


The following commit(s) were added to refs/heads/branch_9x by this push:
     new 79b9c80a286 SOLR-15771: bin/solr auth enable should model best practices for security.json (#1851)
79b9c80a286 is described below

commit 79b9c80a28634bea6859906dee4b1ff886bcf60c
Author: Eric Pugh <ep...@opensourceconnections.com>
AuthorDate: Tue Sep 12 14:44:23 2023 -0400

    SOLR-15771: bin/solr auth enable should model best practices for security.json (#1851)
    
    Introduce a security.json that defines four roles: `search`, `index`, `admin` and `superadmin`, and assigns the `superadmin` to the user created by running bin/solr auth.
---
 solr/CHANGES.txt                                   |  2 +
 .../src/java/org/apache/solr/cli/AuthTool.java     | 57 ++++++++---------
 solr/core/src/resources/security.json              | 74 ++++++++++++++++++++++
 solr/packaging/test/test_auth.bats                 |  3 +-
 solr/packaging/test/test_ssl.bats                  |  2 +-
 solr/solr-ref-guide/antora.template.yml            |  2 +-
 solr/solr-ref-guide/build.gradle                   |  4 +-
 .../pages/solr-control-script-reference.adoc       | 45 ++++---------
 8 files changed, 122 insertions(+), 67 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index d150c85f4ed..e25da121cf8 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -12,6 +12,8 @@ New Features
 
 * SOLR-16954: Make Circuit Breakers available for Update Requests (janhoy, Christine Poerschke, Pierre Salagnac)
 
+* SOLR-15771: bin/auth creates reasonable roles and permissions for security: 'search', 'index', 'admin', and 'superadmin' and assigns user superadmin role. (Eric Pugh, janhoy)
+
 Improvements
 ---------------------
 * SOLR-16490: `/admin/cores?action=backupcore` now has a v2 equivalent, available at
diff --git a/solr/core/src/java/org/apache/solr/cli/AuthTool.java b/solr/core/src/java/org/apache/solr/cli/AuthTool.java
index 62e93e1884b..c5b1153e09d 100644
--- a/solr/core/src/java/org/apache/solr/cli/AuthTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/AuthTool.java
@@ -17,10 +17,15 @@
 
 package org.apache.solr.cli;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.io.Console;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -37,6 +42,7 @@ import org.apache.lucene.util.Constants;
 import org.apache.solr.client.solrj.impl.SolrZkClientTimeout;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.SolrCore;
 import org.apache.solr.security.Sha256AuthenticationProvider;
 import org.apache.zookeeper.KeeperException;
 
@@ -362,37 +368,26 @@ public class AuthTool extends ToolBase {
 
         boolean blockUnknown = Boolean.parseBoolean(cli.getOptionValue("blockUnknown", "true"));
 
-        String securityJson =
-            "{"
-                + "\n  \"authentication\":{"
-                + "\n   \"blockUnknown\": "
-                + blockUnknown
-                + ","
-                + "\n   \"class\":\"solr.BasicAuthPlugin\","
-                + "\n   \"credentials\":{\""
-                + username
-                + "\":\""
-                + Sha256AuthenticationProvider.getSaltedHashedValue(password)
-                + "\"}"
-                + "\n  },"
-                + "\n  \"authorization\":{"
-                + "\n   \"class\":\"solr.RuleBasedAuthorizationPlugin\","
-                + "\n   \"permissions\":["
-                + "\n {\"name\":\"security-edit\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"security-read\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"config-edit\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"config-read\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"collection-admin-edit\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"collection-admin-read\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"core-admin-edit\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"core-admin-read\", \"role\":\"admin\"},"
-                + "\n {\"name\":\"all\", \"role\":\"admin\"}"
-                + "\n   ],"
-                + "\n   \"user-role\":{\""
-                + username
-                + "\":\"admin\"}"
-                + "\n  }"
-                + "\n}";
+        String resourceName = "security.json";
+        final URL resource = SolrCore.class.getClassLoader().getResource(resourceName);
+        if (null == resource) {
+          throw new IllegalArgumentException("invalid resource name: " + resourceName);
+        }
+
+        ObjectMapper mapper = new ObjectMapper();
+        JsonNode securityJson1 = mapper.readTree(resource.openStream());
+        ((ObjectNode) securityJson1).put("blockUnknown", blockUnknown);
+        JsonNode credentialsNode = securityJson1.get("authentication").get("credentials");
+        ((ObjectNode) credentialsNode)
+            .put(username, Sha256AuthenticationProvider.getSaltedHashedValue(password));
+        JsonNode userRoleNode = securityJson1.get("authorization").get("user-role");
+        String[] predefinedRoles = {"superadmin", "admin", "search", "index"};
+        ArrayNode rolesNode = mapper.createArrayNode();
+        for (String role : predefinedRoles) {
+          rolesNode.add(role);
+        }
+        ((ObjectNode) userRoleNode).set(username, rolesNode);
+        String securityJson = securityJson1.toPrettyString();
 
         if (!updateIncludeFileOnly) {
           echoIfVerbose("Uploading following security.json: " + securityJson, cli);
diff --git a/solr/core/src/resources/security.json b/solr/core/src/resources/security.json
new file mode 100644
index 00000000000..f503f7c4e30
--- /dev/null
+++ b/solr/core/src/resources/security.json
@@ -0,0 +1,74 @@
+{
+  "authentication": {
+    "blockUnknown": false,
+    "class": "solr.BasicAuthPlugin",
+    "credentials": {
+      "search": "9ch2qWOmNSeGpfcgLRXafhm5z3KeRti5qCNLn7SmK1I= aXNjZWd4YW9mMzZ0cjE1Nw==",
+      "index": "of9xlSadImtR0MH4obzJvKSZkuE5DIJh5NOui2hWDeA= dTRuYzU4Y3F4N2hxd2sxeA==",
+      "admin": "6clS8rTEj1x1LP/uRCxOZsLdps7Sovokru09WdJX+7A= NGMyZGFhN2lrNHFsdXZybA==",
+      "superadmin": "9wzPajmLBIIi8BmToy8lxveDxfL6Vl/BX/Ss3xrs3XQ= OWZna2hwendocXFnODU5ZQ=="
+    }
+  },
+  "authorization": {
+    "class": "solr.RuleBasedAuthorizationPlugin",
+    "permissions": [{
+        "name": "security-edit",
+        "role": "superadmin"
+      },
+      {
+        "name": "security-read",
+        "role": "admin"
+      },
+      {
+        "name": "config-edit",
+        "role": "admin"
+      },
+      {
+        "name": "config-read",
+        "role": "admin"
+      },
+      {
+        "name": "collection-admin-edit",
+        "role": "admin"
+      },
+      {
+        "name": "core-admin-edit",
+        "role": "admin"
+      },
+      {
+        "name": "core-admin-read",
+        "role": "admin"
+      },
+      {
+        "name": "read",
+        "role": "search"
+      },
+      {
+        "name": "collection-admin-read",
+        "role": "search"
+      },
+      {
+        "name": "update",
+        "role": "index"
+      },
+      {
+        "name": "health",
+        "role": null
+      },
+      {
+        "name": "metrics-read",
+        "role": null
+      },
+      {
+        "name": "all",
+        "role": "admin"
+      }
+    ],
+    "user-role": {
+      "search": ["search"],
+      "index": ["index", "search"],
+      "admin": ["admin", "index", "search"],
+      "superadmin": ["superadmin", "admin", "index", "search"]
+    }
+  }
+}
diff --git a/solr/packaging/test/test_auth.bats b/solr/packaging/test/test_auth.bats
index 666fcb8ee7a..99a6480a59f 100644
--- a/solr/packaging/test/test_auth.bats
+++ b/solr/packaging/test/test_auth.bats
@@ -23,6 +23,8 @@ setup() {
   run solr auth disable
 }
 
+# Note: there are additional auth related tests in test_ssl.bats
+
 @test "auth rejects blockUnknown option with invalid boolean" {
   run ! solr auth enable -type basicAuth -credentials any:any -blockUnknown ture
   assert_output --partial "Argument [blockUnknown] must be either true or false, but was [ture]"
@@ -32,4 +34,3 @@ setup() {
   run ! solr auth enable -type basicAuth -credentials any:any -updateIncludeFileOnly ture
   assert_output --partial "Argument [updateIncludeFileOnly] must be either true or false, but was [ture]"
 }
-
diff --git a/solr/packaging/test/test_ssl.bats b/solr/packaging/test/test_ssl.bats
index f3aae8d6edc..9fdcbd43a59 100644
--- a/solr/packaging/test/test_ssl.bats
+++ b/solr/packaging/test/test_ssl.bats
@@ -138,7 +138,7 @@ teardown() {
 
   # When the Jenkins box "curl" supports --fail-with-body, add "--fail-with-body" and change "run" to "run !", to expect a failure
   run curl --http2 --cacert "$ssl_dir/solr-ssl.pem" 'https://localhost:8983/solr/test/select?q=*:*'
-  assert_output --partial '401 require authentication'
+  assert_output --partial 'Error 401 Authentication'
 }
 
 @test "start solr with client truststore and security manager" {
diff --git a/solr/solr-ref-guide/antora.template.yml b/solr/solr-ref-guide/antora.template.yml
index 8f3d62e5522..30246b6aaf1 100644
--- a/solr/solr-ref-guide/antora.template.yml
+++ b/solr/solr-ref-guide/antora.template.yml
@@ -54,4 +54,4 @@ asciidoc:
     dep-version-tika: '${dep_version_tika}'
     dep-version-zookeeper: '${dep_version_zookeeper}'
     dep-version-lucene: '${dep_version_lucene}'
-    dep-version-opentelemetry: '${dep_version_opentelemetry}'
\ No newline at end of file
+    dep-version-opentelemetry: '${dep_version_opentelemetry}'
diff --git a/solr/solr-ref-guide/build.gradle b/solr/solr-ref-guide/build.gradle
index 0c42b97029b..39554ab7783 100644
--- a/solr/solr-ref-guide/build.gradle
+++ b/solr/solr-ref-guide/build.gradle
@@ -59,9 +59,9 @@ dependencies {
 }
 
 ext {
-    antoraVersion = "3.0.1"
+    antoraVersion = "3.1.4"
     antoraLunrExtensionVersion = "1.0.0-alpha.8"
-    asciidoctorMathjaxVersion = "0.0.8"
+    asciidoctorMathjaxVersion = "0.0.9"
     linkCheckerVersion = "1.4.2"
     gulpCliVersion = "2.3.0"
     // Most recent commit as of 2022-06-24, this repo does not have tags
diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
index 7dfbc228037..88d3a192ef6 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
@@ -995,11 +995,13 @@ This option is useful if you are running multiple Solr instances on the same hos
 
 == Authentication
 
-The `bin/solr` script allows enabling or disabling Basic Authentication, allowing you to configure authentication from the command line.
+The `bin/solr` script allows enabling or disabling Authentication, allowing you to configure authentication from the command line.
 
-Currently, this script only enables Basic Authentication, and is only available when using SolrCloud mode.
+Currently this command is only available when using SolrCloud mode and must be run on the machine hosting Solr.  
+
+For Basic Authentication the script provides https://github.com/apache/solr/blob/main/solr/core/resources/security.json[user roles and permission mappings], and maps the created user to the `superadmin` role.
+For Kerberos it only enables the security.json, it doesn't set up any users or role mappings.  
 
-Must be run on the machine hosting Solr.
 
 === Enabling Basic Authentication
 
@@ -1010,28 +1012,8 @@ For more information on Basic Authentication support specifically, see the secti
 
 The `bin/solr auth enable` command makes several changes to enable Basic Authentication:
 
-* Creates a `security.json` file and uploads it to ZooKeeper.
-The `security.json` file will look similar to:
+* Take the base https://github.com/apache/solr/blob/main/solr/core/resources/security.json[security.json] file, evolves it using `auth` command parameters, and uploads the new file to ZooKeeper.
 +
-[source,json]
-----
-{
-  "authentication":{
-   "blockUnknown": false,
-   "class":"solr.BasicAuthPlugin",
-   "credentials":{"user":"vgGVo69YJeUg/O6AcFiowWsdyOUdqfQvOLsrpIPMCzk= 7iTnaKOWe+Uj5ZfGoKKK2G6hrcF10h6xezMQK+LBvpI="}
-  },
-  "authorization":{
-   "class":"solr.RuleBasedAuthorizationPlugin",
-   "permissions":[
- {"name":"security-edit", "role":"admin"},
- {"name":"collection-admin-edit", "role":"admin"},
- {"name":"core-admin-edit", "role":"admin"}
-   ],
-   "user-role":{"user":"admin"}
-  }
-}
-----
 * Adds two lines to `bin/solr.in.sh` or `bin\solr.in.cmd` to set the authentication type, and the path to `basicAuth.conf`:
 +
 [source,subs="attributes"]
@@ -1099,13 +1081,14 @@ When `false`, unauthenticated users will still be able to access Solr, but only
 +
 Specify the full path to the include file in the environment.
 If not specified this script looks for an include file named solr.in.sh to set environment variables. Specifically, the following locations are searched in this order:
-    <script location>/.
-    $HOME/.solr.in.sh
-    /usr/share/solr
-    /usr/local/share/solr
-    /etc/default
-    /var/solr
-    /opt/solr
++
+* `<script location>/.`
+* `$HOME/.solr.in.sh`
+* `/usr/share/solr`
+* `/usr/local/share/solr`
+* `/etc/default`
+* `/var/solr`
+* `/opt/solr`
 
 `-updateIncludeFileOnly <true|false>`::
 +