This is an automated email from the ASF dual-hosted git repository.
gerlowskija 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 b12604e2f80 Fix 'path' and 'permission' related NPEs
b12604e2f80 is described below
commit b12604e2f8026ba5c5759c720109b14f60a5811a
Author: Jason Gerlowski <[email protected]>
AuthorDate: Wed Jan 14 12:12:04 2026 -0500
Fix 'path' and 'permission' related NPEs
Fixes another lingering source of NPEs in v1 and v2 requests.
---
solr/core/src/java/org/apache/solr/api/V2HttpCall.java | 6 ++++--
.../src/java/org/apache/solr/handler/SchemaHandler.java | 11 ++++++++---
.../java/org/apache/solr/handler/SolrConfigHandler.java | 5 ++---
.../apache/solr/handler/admin/CollectionsHandler.java | 4 +++-
.../org/apache/solr/handler/admin/ConfigSetsHandler.java | 3 ++-
.../java/org/apache/solr/handler/admin/InfoHandler.java | 4 +++-
.../apache/solr/handler/admin/SecurityConfHandler.java | 3 ++-
.../apache/solr/handler/admin/ZookeeperInfoHandler.java | 9 ++++++++-
.../solr/security/RuleBasedAuthorizationPluginBase.java | 12 ++++++++++++
.../src/java/org/apache/solr/servlet/HttpSolrCall.java | 16 ++++++++++++----
10 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
index 24cb696aeee..3bf13188349 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -169,7 +169,8 @@ public class V2HttpCall extends HttpSolrCall {
if (action == REMOTEQUERY) {
action = ADMIN_OR_REMOTEQUERY;
coreUrl = coreUrl.replace("/solr/", "/solr/____v2/c/");
- this.path = path = path.substring(prefix.length() +
collectionName.length() + 2);
+ normalizeAndSetPath(path.substring(prefix.length() +
collectionName.length() + 2));
+ path = this.path;
return;
}
}
@@ -187,7 +188,8 @@ public class V2HttpCall extends HttpSolrCall {
}
Thread.currentThread().setContextClassLoader(core.getResourceLoader().getClassLoader());
- this.path = path = path.substring(prefix.length() +
pathSegments.get(1).length() + 2);
+ normalizeAndSetPath(path.substring(prefix.length() +
pathSegments.get(1).length() + 2));
+ path = this.path;
// Core-level API, so populate "collection" template val
parts.put(COLLECTION_PROP, origCorename);
Api apiInfo = getApiInfo(core.getRequestHandlers(), path,
req.getMethod(), fullPath, parts);
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index 86a5c8b2323..5988989e3dc 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -103,8 +103,7 @@ public class SchemaHandler extends RequestHandlerBase
handleGET(req, rsp);
break;
default:
- throw new SolrException(
- SolrException.ErrorCode.BAD_REQUEST, "Unexpected HTTP method: " +
httpMethod);
+ throw getUnexpectedHttpMethodException(httpMethod.name());
}
}
@@ -118,10 +117,16 @@ public class SchemaHandler extends RequestHandlerBase
case "POST":
return PermissionNameProvider.Name.SCHEMA_EDIT_PERM;
default:
- return null;
+ throw getUnexpectedHttpMethodException(ctx.getHttpMethod());
}
}
+ public static SolrException getUnexpectedHttpMethodException(String
methodName)
+ throws SolrException {
+ return new SolrException(
+ SolrException.ErrorCode.BAD_REQUEST, "Unexpected HTTP method: " +
methodName);
+ }
+
private void handleGET(SolrQueryRequest req, SolrQueryResponse rsp) {
try {
String path = (String) req.getContext().get("path");
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index a9cb278b2f0..e25d661faeb 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -153,8 +153,7 @@ public class SolrConfigHandler extends RequestHandlerBase
command.handleGET();
break;
default:
- throw new SolrException(
- SolrException.ErrorCode.BAD_REQUEST, "Unexpected HTTP method: " +
httpMethod);
+ throw
SchemaHandler.getUnexpectedHttpMethodException(httpMethod.name());
}
}
@@ -961,7 +960,7 @@ public class SolrConfigHandler extends RequestHandlerBase
case "POST":
return Name.CONFIG_EDIT_PERM;
default:
- return null;
+ throw
SchemaHandler.getUnexpectedHttpMethodException(ctx.getHttpMethod());
}
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index f5ee17d6040..b172deeb558 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -251,7 +251,9 @@ public class CollectionsHandler extends RequestHandlerBase
implements Permission
if (action == null) return PermissionNameProvider.Name.COLL_READ_PERM;
CollectionParams.CollectionAction collectionAction =
CollectionParams.CollectionAction.get(action);
- if (collectionAction == null) return null;
+ if (collectionAction == null) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown
action: " + action);
+ }
return collectionAction.isWrite
? PermissionNameProvider.Name.COLL_EDIT_PERM
: PermissionNameProvider.Name.COLL_READ_PERM;
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
index 535deb54e44..ab6ca4f6bcb 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
@@ -205,6 +205,7 @@ public class ConfigSetsHandler extends RequestHandlerBase
implements PermissionN
return Name.CONFIG_READ_PERM;
}
}
- return null;
+
+ throw new SolrException(ErrorCode.BAD_REQUEST, "Required parameter
'action' not provided");
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
index 455bd361247..8b587a32fc2 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
@@ -190,7 +190,9 @@ public class InfoHandler extends RequestHandlerBase {
if (handler != null) {
return handler.getPermissionName(request);
} else {
- return null;
+ throw new SolrException(
+ SolrException.ErrorCode.BAD_REQUEST,
+ "Unable to identify 'info' sub-handler for path " + path);
}
}
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
index f5b528f3d70..0f3cc35d062 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
@@ -43,6 +43,7 @@ import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.RequestHandlerUtils;
+import org.apache.solr.handler.SchemaHandler;
import org.apache.solr.handler.admin.api.GetAuthenticationConfigAPI;
import org.apache.solr.handler.admin.api.GetAuthorizationConfigAPI;
import org.apache.solr.handler.admin.api.ModifyNoAuthPluginSecurityConfigAPI;
@@ -75,7 +76,7 @@ public abstract class SecurityConfHandler extends
RequestHandlerBase
case "POST":
return PermissionNameProvider.Name.SECURITY_EDIT_PERM;
default:
- return null;
+ throw
SchemaHandler.getUnexpectedHttpMethodException(ctx.getHttpMethod());
}
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
index b5a8234a321..ed46a25f20f 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
@@ -40,6 +40,7 @@ import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.util.BytesRef;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
@@ -55,6 +56,7 @@ import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.SuppressForbidden;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.RequestHandlerBase;
@@ -105,7 +107,7 @@ public final class ZookeeperInfoHandler extends
RequestHandlerBase {
@Override
public Name getPermissionName(AuthorizationContext request) {
var params = request.getParams();
- String path = params.get(PATH, "");
+ String path = normalizePath(params.get(PATH, ""));
String detail = params.get(PARAM_DETAIL, "false");
if ("/security.json".equalsIgnoreCase(path) &&
"true".equalsIgnoreCase(detail)) {
return Name.SECURITY_READ_PERM;
@@ -425,6 +427,11 @@ public final class ZookeeperInfoHandler extends
RequestHandlerBase {
rsp.getValues().add(RawResponseWriter.CONTENT, printer);
}
+ @SuppressForbidden(reason = "JDK String class doesn't offer a stripEnd
equivalent")
+ private String normalizePath(String path) {
+ return StringUtils.stripEnd(path, "/");
+ }
+
//
--------------------------------------------------------------------------------------
//
//
--------------------------------------------------------------------------------------
diff --git
a/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPluginBase.java
b/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPluginBase.java
index 7c37e034c73..e126b453f1d 100644
---
a/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPluginBase.java
+++
b/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPluginBase.java
@@ -30,12 +30,14 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.solr.api.AnnotatedApi;
import org.apache.solr.api.Api;
+import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
import org.apache.solr.common.util.CommandOperation;
import org.apache.solr.common.util.ValidatingJsonMap;
@@ -229,6 +231,16 @@ public abstract class RuleBasedAuthorizationPluginBase
} else {
PermissionNameProvider handler = (PermissionNameProvider)
context.getHandler();
PermissionNameProvider.Name permissionName =
handler.getPermissionName(context);
+ if (permissionName == null) {
+ final var errorMessage =
+ String.format(
+ Locale.ROOT,
+ "Unable to find 'predefined' associated with requestHandler
[%s] and request [%s %s]",
+ handler.getClass().getName(),
+ context.getHttpMethod(),
+ context.getResource());
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
errorMessage);
+ }
boolean applies =
permissionName != null &&
predefinedPermission.name.equals(permissionName.name);
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 93feb4b5d15..4fab7a6af83 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -62,6 +62,7 @@ import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.jcip.annotations.ThreadSafe;
+import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
@@ -183,6 +184,8 @@ public class HttpSolrCall {
this.response = response;
this.retry = retry;
this.requestType = RequestType.UNKNOWN;
+ normalizeAndSetPath(ServletUtils.getPathAfterContext(req));
+
req.setAttribute(HttpSolrCall.class.getName(), this);
// set a request timer which can be reused by requests if needed
req.setAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE, new
RTimerTree());
@@ -191,6 +194,11 @@ public class HttpSolrCall {
path = ServletUtils.getPathAfterContext(req);
}
+ @SuppressForbidden(reason = "JDK String class doesn't offer a stripEnd
equivalent")
+ protected void normalizeAndSetPath(String unnormalizedPath) {
+ this.path = StringUtils.stripEnd(unnormalizedPath, "/");
+ }
+
public String getPath() {
return path;
}
@@ -242,7 +250,7 @@ public class HttpSolrCall {
// Try to resolve a Solr core name
core = cores.getCore(origCorename);
if (core != null) {
- path = path.substring(idx);
+ normalizeAndSetPath(path.substring(idx));
} else {
// extra mem barriers, so don't look at this before trying to get core
if (cores.isCoreLoading(origCorename)) {
@@ -251,7 +259,7 @@ public class HttpSolrCall {
// the core may have just finished loading
core = cores.getCore(origCorename);
if (core != null) {
- path = path.substring(idx);
+ normalizeAndSetPath(path.substring(idx));
} else {
if (!cores.isZooKeeperAware()) {
core = cores.getCore("");
@@ -280,14 +288,14 @@ public class HttpSolrCall {
core = getCoreByCollection(collectionName, isPreferLeader);
if (core != null) {
if (idx > 0) {
- path = path.substring(idx);
+ normalizeAndSetPath(path.substring(idx));
}
} else {
// if we couldn't find it locally, look on other nodes
if (idx > 0) {
extractRemotePath(collectionName, origCorename);
if (action == REMOTEQUERY) {
- path = path.substring(idx);
+ normalizeAndSetPath(path.substring(idx));
return;
}
}