You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2019/04/15 19:46:16 UTC
[lucene-solr] branch branch_8x updated: SOLR-12371: Editing
authorization config via REST API now works in standalone mode
This is an automated email from the ASF dual-hosted git repository.
janhoy pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/branch_8x by this push:
new 7f51292 SOLR-12371: Editing authorization config via REST API now works in standalone mode
7f51292 is described below
commit 7f512921569ea4b20316a8d1322630a375ad2730
Author: Jan Høydahl <ja...@apache.org>
AuthorDate: Mon Apr 15 21:09:30 2019 +0200
SOLR-12371: Editing authorization config via REST API now works in standalone mode
(cherry picked from commit 9707bb6fa91ea3062a404690aa7d041771f22746)
---
solr/CHANGES.txt | 3 +-
.../java/org/apache/solr/core/CoreContainer.java | 20 ++++++--
.../solr/security/BasicAuthStandaloneTest.java | 59 ++++++++++++++--------
3 files changed, 54 insertions(+), 28 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 9843245..45029b2 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -163,10 +163,11 @@ Bug Fixes
* SOLR-13336: add maxBooleanClauses (default to 1024) setting to solr.xml, reverting previous effective
value of Integer.MAX_VALUE-1, to restrict risk of pathalogical query expansion. (hossman)
- * SOLR-13386: OverseerTaskQueue#remove should not throw an exception when no node exists after an exists
+* SOLR-13386: OverseerTaskQueue#remove should not throw an exception when no node exists after an exists
check and the Overseer work loop should not allow free spinning the loop when it hits a KeeperException.
(Mark Miller, Fernandez-Lobbe, Mike Drob)
+* SOLR-12371: Editing authorization config via REST API now works in standalone mode (janhoy)
Improvements
----------------------
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index a8e573a..966a4b8 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -337,6 +337,7 @@ public class CoreContainer {
private synchronized void initializeAuthorizationPlugin(Map<String, Object> authorizationConf) {
authorizationConf = Utils.getDeepCopy(authorizationConf, 4);
+ int newVersion = readVersion(authorizationConf);
//Initialize the Authorization module
SecurityPluginHolder<AuthorizationPlugin> old = authorizationPlugin;
SecurityPluginHolder<AuthorizationPlugin> authorizationPlugin = null;
@@ -345,11 +346,12 @@ public class CoreContainer {
if (klas == null) {
throw new SolrException(ErrorCode.SERVER_ERROR, "class is required for authorization plugin");
}
- if (old != null && old.getZnodeVersion() == readVersion(authorizationConf)) {
+ if (old != null && old.getZnodeVersion() == newVersion && newVersion > 0) {
+ log.debug("Authorization config not modified");
return;
}
log.info("Initializing authorization plugin: " + klas);
- authorizationPlugin = new SecurityPluginHolder<>(readVersion(authorizationConf),
+ authorizationPlugin = new SecurityPluginHolder<>(newVersion,
getResourceLoader().newInstance(klas, AuthorizationPlugin.class));
// Read and pass the authorization context to the plugin
@@ -369,6 +371,7 @@ public class CoreContainer {
private void initializeAuditloggerPlugin(Map<String, Object> auditConf) {
auditConf = Utils.getDeepCopy(auditConf, 4);
+ int newVersion = readVersion(auditConf);
//Initialize the Auditlog module
SecurityPluginHolder<AuditLoggerPlugin> old = auditloggerPlugin;
SecurityPluginHolder<AuditLoggerPlugin> newAuditloggerPlugin = null;
@@ -377,11 +380,12 @@ public class CoreContainer {
if (klas == null) {
throw new SolrException(ErrorCode.SERVER_ERROR, "class is required for auditlogger plugin");
}
- if (old != null && old.getZnodeVersion() == readVersion(auditConf)) {
+ if (old != null && old.getZnodeVersion() == newVersion && newVersion > 0) {
+ log.debug("Auditlogger config not modified");
return;
}
log.info("Initializing auditlogger plugin: " + klas);
- newAuditloggerPlugin = new SecurityPluginHolder<>(readVersion(auditConf),
+ newAuditloggerPlugin = new SecurityPluginHolder<>(newVersion,
getResourceLoader().newInstance(klas, AuditLoggerPlugin.class));
newAuditloggerPlugin.plugin.init(auditConf);
@@ -401,6 +405,7 @@ public class CoreContainer {
private synchronized void initializeAuthenticationPlugin(Map<String, Object> authenticationConfig) {
authenticationConfig = Utils.getDeepCopy(authenticationConfig, 4);
+ int newVersion = readVersion(authenticationConfig);
String pluginClassName = null;
if (authenticationConfig != null) {
if (authenticationConfig.containsKey("class")) {
@@ -422,10 +427,15 @@ public class CoreContainer {
SecurityPluginHolder<AuthenticationPlugin> old = authenticationPlugin;
SecurityPluginHolder<AuthenticationPlugin> authenticationPlugin = null;
+ if (old != null && old.getZnodeVersion() == newVersion && newVersion > 0) {
+ log.debug("Authentication config not modified");
+ return;
+ }
+
// Initialize the plugin
if (pluginClassName != null) {
log.info("Initializing authentication plugin: " + pluginClassName);
- authenticationPlugin = new SecurityPluginHolder<>(readVersion(authenticationConfig),
+ authenticationPlugin = new SecurityPluginHolder<>(newVersion,
getResourceLoader().newInstance(pluginClassName,
AuthenticationPlugin.class,
null,
diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java
index 381a1fb..0f3e140 100644
--- a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java
+++ b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java
@@ -16,11 +16,13 @@
*/
package org.apache.solr.security;
+import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Collections;
import java.util.Properties;
import org.apache.http.HttpResponse;
@@ -30,14 +32,10 @@ import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.AbstractHttpMessage;
import org.apache.http.message.BasicHeader;
import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.HttpClientUtil;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
-import org.apache.solr.client.solrj.request.RequestWriter.StringPayloadContentWriter;
-import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.util.Base64;
import org.apache.solr.common.util.Utils;
import org.apache.solr.handler.admin.SecurityConfHandler;
@@ -86,6 +84,7 @@ public class BasicAuthStandaloneTest extends SolrTestCaseJ4 {
public void testBasicAuth() throws Exception {
String authcPrefix = "/admin/authentication";
+ String authzPrefix = "/admin/authorization";
HttpClient cl = null;
HttpSolrClient httpSolrClient = null;
@@ -106,34 +105,35 @@ public class BasicAuthStandaloneTest extends SolrTestCaseJ4 {
"'set-user': {'harry':'HarryIsCool'}\n" +
"}";
- GenericSolrRequest genericReq = new GenericSolrRequest(SolrRequest.METHOD.POST, authcPrefix, new ModifiableSolrParams());
- genericReq.setContentWriter(new StringPayloadContentWriter(command, CommonParams.JSON_MIME));
-
- HttpSolrClient finalHttpSolrClient = httpSolrClient;
- HttpSolrClient.RemoteSolrException exp = expectThrows(HttpSolrClient.RemoteSolrException.class, () -> {
- finalHttpSolrClient.request(genericReq);
- });
- assertEquals(401, exp.code());
+ doHttpPost(cl, baseUrl + authcPrefix, command, null, null, 401);
+ verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication.enabled", "true", 20);
command = "{\n" +
"'set-user': {'harry':'HarryIsUberCool'}\n" +
"}";
- HttpPost httpPost = new HttpPost(baseUrl + authcPrefix);
- setBasicAuthHeader(httpPost, "solr", "SolrRocks");
- httpPost.setEntity(new ByteArrayEntity(command.getBytes(UTF_8)));
- httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
- verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication.enabled", "true", 20);
- HttpResponse r = cl.execute(httpPost);
- int statusCode = r.getStatusLine().getStatusCode();
- Utils.consumeFully(r.getEntity());
- assertEquals("proper_cred sent, but access denied", 200, statusCode);
+ doHttpPost(cl, baseUrl + authcPrefix, command, "solr", "SolrRocks");
verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication/credentials/harry", NOT_NULL_PREDICATE, 20);
// Read file from SOLR_HOME and verify that it contains our new user
assertTrue(new String(Utils.toJSON(securityConfHandler.getSecurityConfig(false).getData()),
Charset.forName("UTF-8")).contains("harry"));
+
+ // Edit authorization
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[1]/role", null, 20);
+ doHttpPost(cl, baseUrl + authzPrefix, "{'set-permission': {'name': 'update', 'role':'updaterole'}}", "solr", "SolrRocks");
+ command = "{\n" +
+ "'set-permission': {'name': 'read', 'role':'solr'}\n" +
+ "}";
+ doHttpPost(cl, baseUrl + authzPrefix, command, "solr", "SolrRocks");
+ try {
+ httpSolrClient.query("collection1", new MapSolrParams(Collections.singletonMap("q", "foo")));
+ fail("Should return a 401 response");
+ } catch (Exception e) {
+ // Test that the second doPost request to /security/authorization went through
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[2]/role", "solr", 20);
+ }
} finally {
if (cl != null) {
HttpClientUtil.close(cl);
@@ -142,6 +142,21 @@ public class BasicAuthStandaloneTest extends SolrTestCaseJ4 {
}
}
+ private void doHttpPost(HttpClient cl, String url, String jsonCommand, String basicUser, String basicPass) throws IOException {
+ doHttpPost(cl, url, jsonCommand, basicUser, basicPass, 200);
+ }
+
+ private void doHttpPost(HttpClient cl, String url, String jsonCommand, String basicUser, String basicPass, int expectStatusCode) throws IOException {
+ HttpPost httpPost = new HttpPost(url);
+ setBasicAuthHeader(httpPost, basicUser, basicPass);
+ httpPost.setEntity(new ByteArrayEntity(jsonCommand.replaceAll("'", "\"").getBytes(UTF_8)));
+ httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
+ HttpResponse r = cl.execute(httpPost);
+ int statusCode = r.getStatusLine().getStatusCode();
+ Utils.consumeFully(r.getEntity());
+ assertEquals("proper_cred sent, but access denied", expectStatusCode, statusCode);
+ }
+
public static void setBasicAuthHeader(AbstractHttpMessage httpMsg, String user, String pwd) {
String userPass = user + ":" + pwd;
String encoded = Base64.byteArrayToBase64(userPass.getBytes(UTF_8));