You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by th...@apache.org on 2021/11/03 19:36:48 UTC
[lucene-solr] branch branch_8_11 updated: SOLR-15766:
MultiAuthPlugin should send non-AJAX anonymous requests to the plugin that
allows anonymous requests (#2601) (#2602)
This is an automated email from the ASF dual-hosted git repository.
thelabdude pushed a commit to branch branch_8_11
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/branch_8_11 by this push:
new a32727b SOLR-15766: MultiAuthPlugin should send non-AJAX anonymous requests to the plugin that allows anonymous requests (#2601) (#2602)
a32727b is described below
commit a32727b8796b76113bcfc10aa68568e453fedf2b
Author: Timothy Potter <th...@gmail.com>
AuthorDate: Wed Nov 3 13:36:36 2021 -0600
SOLR-15766: MultiAuthPlugin should send non-AJAX anonymous requests to the plugin that allows anonymous requests (#2601) (#2602)
---
solr/CHANGES.txt | 2 ++
.../org/apache/solr/security/MultiAuthPlugin.java | 28 ++++++++++-----
.../solr/security/multi_auth_plugin_security.json | 8 ++++-
.../apache/solr/security/MultiAuthPluginTest.java | 40 +++++++++++++++++-----
4 files changed, 60 insertions(+), 18 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 037ebbb..2311785 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -46,6 +46,8 @@ Bug Fixes
* SOLR-15676: Fix PeerSync failure due to RealTimeGetComponent returning duplicates. (Ramsey Haddad, Christine Poerschke, David Smiley)
+* SOLR-15766: MultiAuthPlugin should send non-AJAX anonymous requests to the plugin that allows anonymous requests (Timothy Potter, Eric Pugh)
+
Build
---------------------
diff --git a/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java
index 3f782fa..da60eb9 100644
--- a/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java
@@ -59,6 +59,7 @@ public class MultiAuthPlugin extends AuthenticationPlugin implements ConfigEdita
private final Map<String, AuthenticationPlugin> pluginMap = new LinkedHashMap<>();
private final SolrResourceLoader loader;
+ private AuthenticationPlugin allowsUnknown = null; // the first of our plugins that allows anonymous requests
// Get the loader from the CoreContainer so we can load the sub-plugins, such as the BasicAuthPlugin for Basic
public MultiAuthPlugin(CoreContainer cc) {
@@ -145,6 +146,13 @@ public class MultiAuthPlugin extends AuthenticationPlugin implements ConfigEdita
AuthenticationPlugin pluginForScheme = loader.newInstance(clazz, AuthenticationPlugin.class);
pluginForScheme.init(schemeConfig);
pluginMap.put(scheme.toLowerCase(Locale.ROOT), pluginForScheme);
+
+ if (allowsUnknown == null) {
+ if (!Boolean.parseBoolean(String.valueOf(schemeConfig.getOrDefault("blockUnknown", true)))) {
+ // plugin allows anonymous requests, so we'll send any non-AJAX requests without an authorization header to it
+ allowsUnknown = pluginForScheme;
+ }
+ }
}
@Override
@@ -165,21 +173,25 @@ public class MultiAuthPlugin extends AuthenticationPlugin implements ConfigEdita
HttpServletResponse response = (HttpServletResponse) servletResponse;
final String authHeader = request.getHeader(AUTHORIZATION_HEADER);
-
- // if no Authorization header but is an AJAX request, forward to the default scheme so it can handle it
if (authHeader == null) {
- if (BasicAuthPlugin.isAjaxRequest(request)) {
- // use the first scheme listed as the default
- return pluginMap.values().iterator().next().doAuthenticate(request, response, filterChain);
+ // no Authorization header but if it's an AJAX request, forward to the default scheme so it can handle it
+ // otherwise, send to the first plugin that allows blockUnknown = false
+ final AuthenticationPlugin plugin = BasicAuthPlugin.isAjaxRequest(request) ? pluginMap.values().iterator().next() : allowsUnknown;
+ boolean result = false;
+ if (plugin != null) {
+ pluginInRequest.set(plugin);
+ result = plugin.doAuthenticate(request, response, filterChain);
+ } else {
+ response.sendError(ErrorCode.UNAUTHORIZED.code, "No Authorization header");
}
-
- throw new SolrException(ErrorCode.UNAUTHORIZED, "No Authorization header");
+ return result;
}
final String scheme = getSchemeFromAuthHeader(authHeader);
final AuthenticationPlugin plugin = pluginMap.get(scheme);
if (plugin == null) {
- throw new SolrException(ErrorCode.SERVER_ERROR, "Authorization scheme '" + scheme + "' not supported!");
+ response.sendError(ErrorCode.UNAUTHORIZED.code, "Authorization scheme '" + scheme + "' not supported!");
+ return false;
}
pluginInRequest.set(plugin);
diff --git a/solr/core/src/test-files/solr/security/multi_auth_plugin_security.json b/solr/core/src/test-files/solr/security/multi_auth_plugin_security.json
index 0fd98fb..7fac044 100644
--- a/solr/core/src/test-files/solr/security/multi_auth_plugin_security.json
+++ b/solr/core/src/test-files/solr/security/multi_auth_plugin_security.json
@@ -3,7 +3,7 @@
"class": "solr.MultiAuthPlugin",
"schemes": [{
"scheme": "basic",
- "blockUnknown": false,
+ "blockUnknown": true,
"class": "solr.BasicAuthPlugin",
"credentials": {
"admin": "orwp2Ghgj39lmnrZOTm7Qtre1VqHFDfwAEzr0ApbN3Y= Ju5osoAqOX8iafhWpPP01E5P+sg8tK8tHON7rCYZRRw="
@@ -33,6 +33,12 @@
],
"permissions": [
{
+ "name": "k8s-probe-0",
+ "role": null,
+ "collection": null,
+ "path": "/admin/info/system"
+ },
+ {
"name": "read",
"role": [
"admin",
diff --git a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
index 4566185..a02630a 100644
--- a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
+++ b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
@@ -21,6 +21,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
@@ -30,7 +31,9 @@ import java.util.Objects;
import java.util.function.Predicate;
import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.message.BasicHeader;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
@@ -56,7 +59,7 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
private static final String authcPrefix = "/admin/authentication";
private static final String authzPrefix = "/admin/authorization";
-
+
final Predicate<Object> NULL_PREDICATE = Objects::isNull;
SecurityConfHandlerLocalForTesting securityConfHandler;
JettySolrRunner jetty;
@@ -104,8 +107,19 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication/class", "solr.MultiAuthPlugin", 5, user, pass);
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/class", "solr.MultiAuthRuleBasedAuthorizationPlugin", 5, user, pass);
- // For the multi-auth plugin, every command is wrapped with an object that identifies the "scheme"
+ // anonymous requests are blocked by all plugins
+ int statusCode = doHttpGetAnonymous(cl, baseUrl + "/admin/info/system");
+ assertEquals("anonymous get succeeded but should not have", 401, statusCode);
+ // update blockUnknown to allow anonymous for the basic plugin
String command = "{\n" +
+ "'set-property': { 'basic': {'blockUnknown':false} }\n" +
+ "}";
+ doHttpPost(cl, baseUrl + authcPrefix, command, user, pass, 200);
+ statusCode = doHttpGetAnonymous(cl, baseUrl + "/admin/info/system");
+ assertEquals("anonymous get failed but should have succeeded", 200, statusCode);
+
+ // For the multi-auth plugin, every command is wrapped with an object that identifies the "scheme"
+ command = "{\n" +
"'set-user': {'harry':'HarryIsCool'}\n" +
"}";
// no scheme identified!
@@ -141,25 +155,25 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/schemes[0]/user-role/harry", NOT_NULL_PREDICATE, 5, user, pass);
// give the users role a custom permission
- verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[5]", NULL_PREDICATE, 5, user, pass);
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[6]", NULL_PREDICATE, 5, user, pass);
command = "{\n" +
"'set-permission': { 'name':'k8s-zk', 'role':'users', 'collection':null, 'path':'/admin/zookeeper/status' }\n" +
"}";
doHttpPost(cl, baseUrl + authzPrefix, command, user, pass, 200);
- verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[5]/path", new ExpectedValuePredicate("/admin/zookeeper/status"), 5, user, pass);
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[6]/path", new ExpectedValuePredicate("/admin/zookeeper/status"), 5, user, pass);
command = "{\n" +
- "'update-permission': { 'index':'6', 'name':'k8s-zk', 'role':'users', 'collection':null, 'path':'/admin/zookeeper/status2' }\n" +
+ "'update-permission': { 'index':'7', 'name':'k8s-zk', 'role':'users', 'collection':null, 'path':'/admin/zookeeper/status2' }\n" +
"}";
doHttpPost(cl, baseUrl + authzPrefix, command, user, pass, 200);
- verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[5]/path", new ExpectedValuePredicate("/admin/zookeeper/status2"), 5, user, pass);
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[6]/path", new ExpectedValuePredicate("/admin/zookeeper/status2"), 5, user, pass);
// delete the permission
command = "{\n" +
- "'delete-permission': 6\n" +
+ "'delete-permission': 7\n" +
"}";
doHttpPost(cl, baseUrl + authzPrefix, command, user, pass, 200);
- verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[5]", NULL_PREDICATE, 5, user, pass);
+ verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/permissions[6]", NULL_PREDICATE, 5, user, pass);
// delete the user
command = "{\n" +
@@ -186,6 +200,14 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
}
}
+ private int doHttpGetAnonymous(HttpClient cl, String url) throws IOException {
+ HttpGet httpPost = new HttpGet(url);
+ HttpResponse r = cl.execute(httpPost);
+ int statusCode = r.getStatusLine().getStatusCode();
+ Utils.consumeFully(r.getEntity());
+ return statusCode;
+ }
+
private static final class MockPrincipal implements Principal, Serializable {
@Override
public String getName() {
@@ -203,7 +225,7 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
@Override
public boolean doAuthenticate(ServletRequest request, ServletResponse response, FilterChain filterChain) throws Exception {
Principal principal = new MockPrincipal();
- request = wrapWithPrincipal((HttpServletRequest)request, principal, "mock");
+ request = wrapWithPrincipal((HttpServletRequest) request, principal, "mock");
filterChain.doFilter(request, response);
return true;
}