mirror of https://github.com/apache/lucene.git
SOLR-10282: bin/solr support for enabling Kerberos authentication
This commit is contained in:
parent
7051a7919f
commit
5f28780e5d
|
@ -272,6 +272,8 @@ New Features
|
||||||
multivalued fields, a new JSON request language, and more. DocValues are now required for any field used in the analytics
|
multivalued fields, a new JSON request language, and more. DocValues are now required for any field used in the analytics
|
||||||
expression whereas previously docValues was not required. Please see SOLR-10123 for details. (Houston Putman)
|
expression whereas previously docValues was not required. Please see SOLR-10123 for details. (Houston Putman)
|
||||||
|
|
||||||
|
* SOLR-10282: bin/solr support for enabling Kerberos authentication (Ishan Chattopadhyaya)
|
||||||
|
|
||||||
Bug Fixes
|
Bug Fixes
|
||||||
----------------------
|
----------------------
|
||||||
* SOLR-9262: Connection and read timeouts are being ignored by UpdateShardHandler after SOLR-4509.
|
* SOLR-9262: Connection and read timeouts are being ignored by UpdateShardHandler after SOLR-4509.
|
||||||
|
|
|
@ -555,20 +555,23 @@ function print_usage() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "Usage: solr auth enable [-type basicAuth] -credentials user:pass [-blockUnknown <true|false>] [-updateIncludeFileOnly <true|false>]"
|
echo "Usage: solr auth enable [-type basicAuth] -credentials user:pass [-blockUnknown <true|false>] [-updateIncludeFileOnly <true|false>]"
|
||||||
echo " solr auth enable [-type basicAuth] -prompt <true|false> [-blockUnknown <true|false>] [-updateIncludeFileOnly <true|false>]"
|
echo " solr auth enable [-type basicAuth] -prompt <true|false> [-blockUnknown <true|false>] [-updateIncludeFileOnly <true|false>]"
|
||||||
|
echo " solr auth enable -type kerberos -config "<kerberos configs>" [-updateIncludeFileOnly <true|false>]"
|
||||||
echo " solr auth disable [-updateIncludeFileOnly <true|false>]"
|
echo " solr auth disable [-updateIncludeFileOnly <true|false>]"
|
||||||
echo ""
|
echo ""
|
||||||
echo " -type <type> The authentication mechanism to enable. Defaults to 'basicAuth'."
|
echo " -type <type> The authentication mechanism (basicAuth or kerberos) to enable. Defaults to 'basicAuth'."
|
||||||
echo ""
|
echo ""
|
||||||
echo " -credentials <user:pass> The username and password of the initial user"
|
echo " -credentials <user:pass> The username and password of the initial user. Applicable for basicAuth only."
|
||||||
echo " Note: only one of -prompt or -credentials must be provided"
|
echo " Note: only one of -prompt or -credentials must be provided"
|
||||||
echo ""
|
echo ""
|
||||||
echo " -prompt <true|false> Prompts the user to provide the credentials"
|
echo " -config "<configs>" Configuration parameters (Solr startup parameters). Required and applicable only for Kerberos"
|
||||||
|
echo ""
|
||||||
|
echo " -prompt <true|false> Prompts the user to provide the credentials. Applicable for basicAuth only."
|
||||||
echo " Note: only one of -prompt or -credentials must be provided"
|
echo " Note: only one of -prompt or -credentials must be provided"
|
||||||
echo ""
|
echo ""
|
||||||
echo " -blockUnknown <true|false> When true, this blocks out access to unauthenticated users. When not provided,"
|
echo " -blockUnknown <true|false> When true, this blocks out access to unauthenticated users. When not provided,"
|
||||||
echo " this defaults to false (i.e. unauthenticated users can access all endpoints, except the"
|
echo " this defaults to false (i.e. unauthenticated users can access all endpoints, except the"
|
||||||
echo " operations like collection-edit, security-edit, core-admin-edit etc.). Check the reference"
|
echo " operations like collection-edit, security-edit, core-admin-edit etc.). Check the reference"
|
||||||
echo " guide for Basic Authentication for more details."
|
echo " guide for Basic Authentication for more details. Applicable for basicAuth only."
|
||||||
echo ""
|
echo ""
|
||||||
echo " -updateIncludeFileOnly <true|false> Only update the solr.in.sh or solr.in.cmd file, and skip actual enabling/disabling"
|
echo " -updateIncludeFileOnly <true|false> Only update the solr.in.sh or solr.in.cmd file, and skip actual enabling/disabling"
|
||||||
echo " authentication (i.e. don't update security.json)"
|
echo " authentication (i.e. don't update security.json)"
|
||||||
|
@ -1242,6 +1245,11 @@ if [[ "$SCRIPT_CMD" == "auth" ]]; then
|
||||||
AUTH_PARAMS=("${AUTH_PARAMS[@]}" "-credentials" "$AUTH_CREDENTIALS")
|
AUTH_PARAMS=("${AUTH_PARAMS[@]}" "-credentials" "$AUTH_CREDENTIALS")
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
-config)
|
||||||
|
AUTH_CONFIG="`echo $2| base64`"
|
||||||
|
AUTH_PARAMS=("${AUTH_PARAMS[@]}" "-config" "$AUTH_CONFIG")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-solrIncludeFile)
|
-solrIncludeFile)
|
||||||
SOLR_INCLUDE="$2"
|
SOLR_INCLUDE="$2"
|
||||||
shift 2
|
shift 2
|
||||||
|
|
|
@ -43,6 +43,7 @@ import java.time.Instant;
|
||||||
import java.time.Period;
|
import java.time.Period;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -115,6 +116,7 @@ import org.apache.solr.common.params.CommonParams;
|
||||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
import org.apache.solr.common.util.ContentStreamBase;
|
import org.apache.solr.common.util.ContentStreamBase;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
|
import org.apache.solr.common.util.StrUtils;
|
||||||
import org.apache.solr.security.Sha256AuthenticationProvider;
|
import org.apache.solr.security.Sha256AuthenticationProvider;
|
||||||
import org.apache.solr.util.configuration.SSLConfigurationsFactory;
|
import org.apache.solr.util.configuration.SSLConfigurationsFactory;
|
||||||
import org.noggit.CharArr;
|
import org.noggit.CharArr;
|
||||||
|
@ -3548,7 +3550,7 @@ public class SolrCLI {
|
||||||
OptionBuilder
|
OptionBuilder
|
||||||
.withArgName("type")
|
.withArgName("type")
|
||||||
.hasArg()
|
.hasArg()
|
||||||
.withDescription("The authentication mechanism to enable. Defaults to 'basicAuth'.")
|
.withDescription("The authentication mechanism to enable (basicAuth or kerberos). Defaults to 'basicAuth'.")
|
||||||
.create("type"),
|
.create("type"),
|
||||||
OptionBuilder
|
OptionBuilder
|
||||||
.withArgName("credentials")
|
.withArgName("credentials")
|
||||||
|
@ -3561,6 +3563,11 @@ public class SolrCLI {
|
||||||
.withDescription("Prompts the user to provide the credentials. Use either -credentials or -prompt, not both")
|
.withDescription("Prompts the user to provide the credentials. Use either -credentials or -prompt, not both")
|
||||||
.create("prompt"),
|
.create("prompt"),
|
||||||
OptionBuilder
|
OptionBuilder
|
||||||
|
.withArgName("config")
|
||||||
|
.hasArgs()
|
||||||
|
.withDescription("Configuration parameters (Solr startup parameters). Required for Kerberos authentication")
|
||||||
|
.create("config"),
|
||||||
|
OptionBuilder
|
||||||
.withArgName("blockUnknown")
|
.withArgName("blockUnknown")
|
||||||
.withDescription("Blocks all access for unknown users (requires authentication for all endpoints)")
|
.withDescription("Blocks all access for unknown users (requires authentication for all endpoints)")
|
||||||
.hasArg()
|
.hasArg()
|
||||||
|
@ -3603,11 +3610,141 @@ public class SolrCLI {
|
||||||
}
|
}
|
||||||
|
|
||||||
String type = cli.getOptionValue("type", "basicAuth");
|
String type = cli.getOptionValue("type", "basicAuth");
|
||||||
if (type.equalsIgnoreCase("basicAuth") == false) {
|
switch (type) {
|
||||||
System.out.println("Only type=basicAuth supported at the moment.");
|
case "basicAuth":
|
||||||
|
return handleBasicAuth(cli);
|
||||||
|
case "kerberos":
|
||||||
|
return handleKerberos(cli);
|
||||||
|
default:
|
||||||
|
System.out.println("Only type=basicAuth or kerberos supported at the moment.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int handleKerberos(CommandLine cli) throws Exception {
|
||||||
|
String cmd = cli.getArgs()[0];
|
||||||
|
boolean updateIncludeFileOnly = Boolean.parseBoolean(cli.getOptionValue("updateIncludeFileOnly", "false"));
|
||||||
|
String securityJson = "{" +
|
||||||
|
"\n \"authentication\":{" +
|
||||||
|
"\n \"class\":\"solr.KerberosPlugin\"" +
|
||||||
|
"\n }" +
|
||||||
|
"\n}";
|
||||||
|
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case "enable":
|
||||||
|
String zkHost = null;
|
||||||
|
boolean zkInaccessible = false;
|
||||||
|
|
||||||
|
if (!updateIncludeFileOnly) {
|
||||||
|
try {
|
||||||
|
zkHost = getZkHost(cli);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.out.println("Unable to access ZooKeeper. Please add the following security.json to ZooKeeper (in case of SolrCloud):\n"
|
||||||
|
+ securityJson + "\n");
|
||||||
|
zkInaccessible = true;
|
||||||
|
}
|
||||||
|
if (zkHost == null) {
|
||||||
|
if (zkInaccessible == false) {
|
||||||
|
System.out.println("Unable to access ZooKeeper. Please add the following security.json to ZooKeeper (in case of SolrCloud):\n"
|
||||||
|
+ securityJson + "\n");
|
||||||
|
zkInaccessible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if security is already enabled or not
|
||||||
|
if (!zkInaccessible) {
|
||||||
|
try (SolrZkClient zkClient = new SolrZkClient(zkHost, 10000)) {
|
||||||
|
if (zkClient.exists("/security.json", true)) {
|
||||||
|
byte oldSecurityBytes[] = zkClient.getData("/security.json", null, null, true);
|
||||||
|
if (!"{}".equals(new String(oldSecurityBytes, StandardCharsets.UTF_8).trim())) {
|
||||||
|
System.out.println("Security is already enabled. You can disable it with 'bin/solr auth disable'. Existing security.json: \n"
|
||||||
|
+ new String(oldSecurityBytes, StandardCharsets.UTF_8));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (zkInaccessible == false) {
|
||||||
|
System.out.println("Unable to access ZooKeeper. Please add the following security.json to ZooKeeper (in case of SolrCloud):\n"
|
||||||
|
+ securityJson + "\n");
|
||||||
|
zkInaccessible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updateIncludeFileOnly) {
|
||||||
|
if (!zkInaccessible) {
|
||||||
|
System.out.println("Uploading following security.json: " + securityJson);
|
||||||
|
try (SolrZkClient zkClient = new SolrZkClient(zkHost, 10000)) {
|
||||||
|
zkClient.setData("/security.json", securityJson.getBytes(StandardCharsets.UTF_8), true);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (zkInaccessible == false) {
|
||||||
|
System.out.println("Unable to access ZooKeeper. Please add the following security.json to ZooKeeper (in case of SolrCloud):\n"
|
||||||
|
+ securityJson);
|
||||||
|
zkInaccessible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String config = StrUtils.join(Arrays.asList(cli.getOptionValues("config")), ' ');
|
||||||
|
// config is base64 encoded (to get around parsing problems), decode it
|
||||||
|
config = config.replaceAll(" ", "");
|
||||||
|
config = new String(Base64.getDecoder().decode(config.getBytes("UTF-8")), "UTF-8");
|
||||||
|
config = config.replaceAll("\n", "").replaceAll("\r", "");
|
||||||
|
|
||||||
|
String solrIncludeFilename = cli.getOptionValue("solrIncludeFile");
|
||||||
|
File includeFile = new File(solrIncludeFilename);
|
||||||
|
if (includeFile.exists() == false || includeFile.canWrite() == false) {
|
||||||
|
System.out.println("Solr include file " + solrIncludeFilename + " doesn't exist or is not writeable.");
|
||||||
|
printAuthEnablingInstructions(config);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the solr.in.sh file to contain the necessary authentication lines
|
||||||
|
updateIncludeFileEnableAuth(includeFile, null, config);
|
||||||
|
System.out.println("Please restart any running Solr nodes.");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case "disable":
|
||||||
|
if (!updateIncludeFileOnly) {
|
||||||
|
zkHost = getZkHost(cli);
|
||||||
|
if (zkHost == null) {
|
||||||
|
stdout.print("ZK Host not found. Solr should be running in cloud mode");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("Uploading following security.json: {}");
|
||||||
|
|
||||||
|
try (SolrZkClient zkClient = new SolrZkClient(zkHost, 10000)) {
|
||||||
|
zkClient.setData("/security.json", "{}".getBytes(StandardCharsets.UTF_8), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
solrIncludeFilename = cli.getOptionValue("solrIncludeFile");
|
||||||
|
includeFile = new File(solrIncludeFilename);
|
||||||
|
if (!includeFile.exists() || !includeFile.canWrite()) {
|
||||||
|
System.out.println("Solr include file " + solrIncludeFilename + " doesn't exist or is not writeable.");
|
||||||
|
System.out.println("Security has been disabled. Please remove any SOLR_AUTH_TYPE or SOLR_AUTHENTICATION_OPTS configuration from solr.in.sh/solr.in.cmd.\n");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the solr.in.sh file to comment out the necessary authentication lines
|
||||||
|
updateIncludeFileDisableAuth(includeFile);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.out.println("Valid auth commands are: enable, disable");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Options not understood.");
|
||||||
|
new HelpFormatter().printHelp("bin/solr auth <enable|disable> [OPTIONS]", getToolOptions(this));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
private int handleBasicAuth(CommandLine cli) throws Exception {
|
||||||
String cmd = cli.getArgs()[0];
|
String cmd = cli.getArgs()[0];
|
||||||
boolean prompt = Boolean.parseBoolean(cli.getOptionValue("prompt", "false"));
|
boolean prompt = Boolean.parseBoolean(cli.getOptionValue("prompt", "false"));
|
||||||
boolean updateIncludeFileOnly = Boolean.parseBoolean(cli.getOptionValue("updateIncludeFileOnly", "false"));
|
boolean updateIncludeFileOnly = Boolean.parseBoolean(cli.getOptionValue("updateIncludeFileOnly", "false"));
|
||||||
|
@ -3715,7 +3852,7 @@ public class SolrCLI {
|
||||||
"httpBasicAuthUser=" + username + "\nhttpBasicAuthPassword=" + password, StandardCharsets.UTF_8);
|
"httpBasicAuthUser=" + username + "\nhttpBasicAuthPassword=" + password, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
// update the solr.in.sh file to contain the necessary authentication lines
|
// update the solr.in.sh file to contain the necessary authentication lines
|
||||||
updateIncludeFileEnableAuth(includeFile, basicAuthConfFile.getAbsolutePath());
|
updateIncludeFileEnableAuth(includeFile, basicAuthConfFile.getAbsolutePath(), null);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case "disable":
|
case "disable":
|
||||||
|
@ -3754,7 +3891,6 @@ public class SolrCLI {
|
||||||
new HelpFormatter().printHelp("bin/solr auth <enable|disable> [OPTIONS]", getToolOptions(this));
|
new HelpFormatter().printHelp("bin/solr auth <enable|disable> [OPTIONS]", getToolOptions(this));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printAuthEnablingInstructions(String username, String password) {
|
private void printAuthEnablingInstructions(String username, String password) {
|
||||||
if (SystemUtils.IS_OS_WINDOWS) {
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
System.out.println("\nAdd the following lines to the solr.in.cmd file so that the solr.cmd script can use subsequently.\n");
|
System.out.println("\nAdd the following lines to the solr.in.cmd file so that the solr.cmd script can use subsequently.\n");
|
||||||
|
@ -3766,8 +3902,26 @@ public class SolrCLI {
|
||||||
+ "SOLR_AUTHENTICATION_OPTS=\"-Dbasicauth=" + username + ":" + password + "\"\n");
|
+ "SOLR_AUTHENTICATION_OPTS=\"-Dbasicauth=" + username + ":" + password + "\"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void printAuthEnablingInstructions(String kerberosConfig) {
|
||||||
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
|
System.out.println("\nAdd the following lines to the solr.in.cmd file so that the solr.cmd script can use subsequently.\n");
|
||||||
|
System.out.println("set SOLR_AUTH_TYPE=kerberos\n"
|
||||||
|
+ "set SOLR_AUTHENTICATION_OPTS=\"" + kerberosConfig + "\"\n");
|
||||||
|
} else {
|
||||||
|
System.out.println("\nAdd the following lines to the solr.in.sh file so that the ./solr script can use subsequently.\n");
|
||||||
|
System.out.println("SOLR_AUTH_TYPE=\"kerberos\"\n"
|
||||||
|
+ "SOLR_AUTHENTICATION_OPTS=\"" + kerberosConfig + "\"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateIncludeFileEnableAuth(File includeFile, String basicAuthConfFile) throws IOException {
|
/**
|
||||||
|
* This will update the include file (e.g. solr.in.sh / solr.in.cmd) with the authentication parameters.
|
||||||
|
* @param includeFile The include file
|
||||||
|
* @param basicAuthConfFile If basicAuth, the path of the file containing credentials. If not, null.
|
||||||
|
* @param kerberosConfig If kerberos, the config string containing startup parameters. If not, null.
|
||||||
|
*/
|
||||||
|
private void updateIncludeFileEnableAuth(File includeFile, String basicAuthConfFile, String kerberosConfig) throws IOException {
|
||||||
|
assert !(basicAuthConfFile != null && kerberosConfig != null); // only one of the two needs to be populated
|
||||||
List<String> includeFileLines = FileUtils.readLines(includeFile, StandardCharsets.UTF_8);
|
List<String> includeFileLines = FileUtils.readLines(includeFile, StandardCharsets.UTF_8);
|
||||||
for (int i=0; i<includeFileLines.size(); i++) {
|
for (int i=0; i<includeFileLines.size(); i++) {
|
||||||
String line = includeFileLines.get(i);
|
String line = includeFileLines.get(i);
|
||||||
|
@ -3780,6 +3934,8 @@ public class SolrCLI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
includeFileLines.add(""); // blank line
|
includeFileLines.add(""); // blank line
|
||||||
|
|
||||||
|
if (basicAuthConfFile != null) { // for basicAuth
|
||||||
if (SystemUtils.IS_OS_WINDOWS) {
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
includeFileLines.add("REM The following lines added by solr.cmd for enabling BasicAuth");
|
includeFileLines.add("REM The following lines added by solr.cmd for enabling BasicAuth");
|
||||||
includeFileLines.add("set SOLR_AUTH_TYPE=basic");
|
includeFileLines.add("set SOLR_AUTH_TYPE=basic");
|
||||||
|
@ -3789,9 +3945,23 @@ public class SolrCLI {
|
||||||
includeFileLines.add("SOLR_AUTH_TYPE=\"basic\"");
|
includeFileLines.add("SOLR_AUTH_TYPE=\"basic\"");
|
||||||
includeFileLines.add("SOLR_AUTHENTICATION_OPTS=\"-Dsolr.httpclient.config=" + basicAuthConfFile + "\"");
|
includeFileLines.add("SOLR_AUTHENTICATION_OPTS=\"-Dsolr.httpclient.config=" + basicAuthConfFile + "\"");
|
||||||
}
|
}
|
||||||
|
} else { // for kerberos
|
||||||
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
|
includeFileLines.add("REM The following lines added by solr.cmd for enabling BasicAuth");
|
||||||
|
includeFileLines.add("set SOLR_AUTH_TYPE=kerberos");
|
||||||
|
includeFileLines.add("set SOLR_AUTHENTICATION_OPTS=\"-Dsolr.httpclient.config=" + basicAuthConfFile + "\"");
|
||||||
|
} else {
|
||||||
|
includeFileLines.add("# The following lines added by ./solr for enabling BasicAuth");
|
||||||
|
includeFileLines.add("SOLR_AUTH_TYPE=\"kerberos\"");
|
||||||
|
includeFileLines.add("SOLR_AUTHENTICATION_OPTS=\"" + kerberosConfig + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
FileUtils.writeLines(includeFile, StandardCharsets.UTF_8.name(), includeFileLines);
|
FileUtils.writeLines(includeFile, StandardCharsets.UTF_8.name(), includeFileLines);
|
||||||
|
|
||||||
System.out.println("Written out credentials file: " + basicAuthConfFile + ", updated Solr include file: " + includeFile.getAbsolutePath() + ".");
|
if (basicAuthConfFile != null) {
|
||||||
|
System.out.println("Written out credentials file: " + basicAuthConfFile);
|
||||||
|
}
|
||||||
|
System.out.println("Updated Solr include file: " + includeFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIncludeFileDisableAuth(File includeFile) throws IOException {
|
private void updateIncludeFileDisableAuth(File includeFile) throws IOException {
|
||||||
|
|
Loading…
Reference in New Issue