SOLR-8048: bin/solr script should support basic auth credentials provided in solr.in.sh

This commit is contained in:
Noble Paul 2016-06-14 19:37:45 +05:30
parent b9ded92295
commit 97e696dd50
3 changed files with 70 additions and 44 deletions

View File

@ -57,7 +57,9 @@ Detailed Change List
New Features
----------------------
* SOLR-9187: Support dates and booleans in /export handler, support boolean DocValues fields
* SOLR-9187: Support dates and booleans in /export handler, support boolean DocValues fields (Erick Erickson)
* SOLR-8048: bin/solr script should support basic auth credentials provided in solr.in.sh (noble)
Bug Fixes

View File

@ -16,8 +16,6 @@
*/
package org.apache.solr.util;
import static org.apache.solr.common.params.CommonParams.NAME;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -56,6 +54,7 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.Executor;
@ -74,6 +73,7 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.lucene.util.Version;
import org.apache.solr.client.solrj.SolrClient;
@ -88,7 +88,6 @@ import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkCoreNodeProps;
@ -97,6 +96,7 @@ import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.noggit.CharArr;
import org.noggit.JSONParser;
import org.noggit.JSONWriter;
@ -104,11 +104,12 @@ import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.common.params.CommonParams.NAME;
/**
* Command-line utility for working with Solr.
*/
public class SolrCLI {
/**
* Defines the interface to a Solr tool that can be run from this command-line app.
*/
@ -139,6 +140,7 @@ public class SolrCLI {
int toolExitStatus = 0;
try {
setBasicAuth(cli);
runImpl(cli);
} catch (Exception exc) {
// since this is a CLI, spare the user the stacktrace
@ -153,6 +155,21 @@ public class SolrCLI {
return toolExitStatus;
}
private void setBasicAuth(CommandLine cli) throws Exception {
String basicauth = System.getProperty("basicauth", null);
if (basicauth != null) {
List<String> ss = StrUtils.splitSmart(basicauth, ':');
if (ss.size() != 2)
throw new Exception("Please provide 'basicauth' in the 'user:password' format");
HttpClientUtil.addRequestInterceptor((httpRequest, httpContext) -> {
String pair = ss.get(0) + ":" + ss.get(1);
byte[] encodedBytes = Base64.encodeBase64(pair.getBytes());
httpRequest.addHeader(new BasicHeader("Authorization", "Basic "+ new String(encodedBytes)));
});
}
}
protected abstract void runImpl(CommandLine cli) throws Exception;
// It's a little awkward putting this in ToolBase, but to re-use it in upconfig and create, _and_ have access

View File

@ -16,7 +16,12 @@
*/
package org.apache.solr.security;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -55,6 +60,7 @@ import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.util.SolrCLI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -129,39 +135,20 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudClusterBase {
"'set-user-role': {'harry':'admin'}\n" +
"}";
httpPost = new HttpPost(baseUrl + authzPrefix);
setBasicAuthHeader(httpPost, "solr", "SolrRocks");
httpPost.setEntity(new ByteArrayEntity(command.getBytes(UTF_8)));
httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
r = cl.execute(httpPost);
assertEquals(200, r.getStatusLine().getStatusCode());
Utils.consumeFully(r.getEntity());
executeCommand(baseUrl + authzPrefix, cl,command, "solr", "SolrRocks");
baseUrl = getRandomReplica(zkStateReader.getClusterState().getCollection(defaultCollName), random()).getStr(BASE_URL_PROP);
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/user-role/harry", NOT_NULL_PREDICATE, 20);
httpPost = new HttpPost(baseUrl + authzPrefix);
setBasicAuthHeader(httpPost, "harry", "HarryIsUberCool");
httpPost.setEntity(new ByteArrayEntity(Utils.toJSON(singletonMap("set-permission", Utils.makeMap
executeCommand(baseUrl + authzPrefix, cl, Utils.toJSONString(singletonMap("set-permission", Utils.makeMap
("collection", "x",
"path", "/update/*",
"role", "dev")))));
httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/user-role/harry", NOT_NULL_PREDICATE, 20);
r = cl.execute(httpPost);
assertEquals(200, r.getStatusLine().getStatusCode());
Utils.consumeFully(r.getEntity());
"role", "dev"))), "harry", "HarryIsUberCool" );
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[1]/collection", "x", 20);
httpPost = new HttpPost(baseUrl + authzPrefix);
setBasicAuthHeader(httpPost, "harry", "HarryIsUberCool");
httpPost.setEntity(new ByteArrayEntity(Utils.toJSON(singletonMap("set-permission", Utils.makeMap
("name","collection-admin-edit", "role", "admin" )))));
r = cl.execute(httpPost);
Utils.consumeFully(r.getEntity());
executeCommand(baseUrl + authzPrefix, cl,Utils.toJSONString(singletonMap("set-permission", Utils.makeMap
("name", "collection-admin-edit", "role", "admin"))), "harry", "HarryIsUberCool" );
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[2]/name", "collection-admin-edit", 20);
CollectionAdminRequest.Reload reload = new CollectionAdminRequest.Reload();
@ -196,14 +183,7 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudClusterBase {
}
cloudSolrClient.setDefaultCollection(old);
httpPost = new HttpPost(baseUrl + authzPrefix);
setBasicAuthHeader(httpPost, "harry", "HarryIsUberCool");
httpPost.setEntity(new ByteArrayEntity("{set-permission : { name : update , role : admin}}".getBytes(UTF_8)));
httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
r = cl.execute(httpPost);
assertEquals(200,r.getStatusLine().getStatusCode());
Utils.consumeFully(r.getEntity());
executeCommand(baseUrl + authzPrefix, cl,"{set-permission : { name : update , role : admin}}", "harry", "HarryIsUberCool");
SolrInputDocument doc = new SolrInputDocument();
doc.setField("id","4");
@ -212,10 +192,42 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudClusterBase {
update.add(doc);
update.setCommitWithin(100);
cloudSolrClient.request(update);
executeCommand(baseUrl + authzPrefix, cl, "{set-property : { blockUnknown: true}}", "harry", "HarryIsUberCool");
String[] toolArgs = new String[]{
"status", "-solr", baseUrl};
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream stdoutSim = new PrintStream(baos, true, StandardCharsets.UTF_8.name());
SolrCLI.StatusTool tool = new SolrCLI.StatusTool(stdoutSim);
try {
System.setProperty("basicauth", "harry:HarryIsUberCool");
tool.runTool(SolrCLI.processCommandLineArgs(SolrCLI.joinCommonAndToolOptions(tool.getOptions()), toolArgs));
Map obj = (Map) Utils.fromJSON(new ByteArrayInputStream(baos.toByteArray()));
assertTrue(obj.containsKey("version"));
assertTrue(obj.containsKey("startTime"));
assertTrue(obj.containsKey("uptime"));
assertTrue(obj.containsKey("memory"));
} catch (Exception e) {
log.error("RunExampleTool failed due to: " + e +
"; stdout from tool prior to failure: " + baos.toString(StandardCharsets.UTF_8.name()));
}
executeCommand(baseUrl + authzPrefix, cl, "{set-property : { blockUnknown: false}}", "harry", "HarryIsUberCool");
HttpClientUtil.close(cl);
}
public static void executeCommand(String url, HttpClient cl, String payload, String user, String pwd) throws IOException {
HttpPost httpPost;
HttpResponse r;
httpPost = new HttpPost(url);
setBasicAuthHeader(httpPost, user, pwd);
httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8)));
httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
r = cl.execute(httpPost);
assertEquals(200, r.getStatusLine().getStatusCode());
Utils.consumeFully(r.getEntity());
}
public static void verifySecurityStatus(HttpClient cl, String url, String objPath, Object expected, int count) throws Exception {
boolean success = false;
String s = null;
@ -262,12 +274,7 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudClusterBase {
return l.isEmpty() ? null : l.get(0);
}
static final Predicate NOT_NULL_PREDICATE = new Predicate() {
@Override
public boolean test(Object o) {
return o != null;
}
};
static final Predicate NOT_NULL_PREDICATE = o -> o != null;
//the password is 'SolrRocks'
//this could be generated everytime. But , then we will not know if there is any regression