This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_10x by this push:
new f39012f8798 Fix 'path' and 'permission' related NPEs
f39012f8798 is described below
commit f39012f879824ad54d0edb9776692c437aeff9fd
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, 55 insertions(+), 18 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 51d14b65993..f8a9daa2389 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -170,7 +170,8 @@ public class V2HttpCall extends HttpSolrCall {
if (action == REMOTEPROXY) {
action = ADMIN_OR_REMOTEPROXY;
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;
}
}
@@ -188,7 +189,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 349b46a9423..cdd745ab3a0 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -118,8 +118,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());
}
}
@@ -133,10 +132,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 7b8d0417d20..cba47bad98d 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -154,8 +154,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());
}
}
@@ -964,7 +963,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 c2cd0148938..4102edff3e1 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
@@ -243,7 +243,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 0f0d79d36b9..edcdc0b1088 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
@@ -203,6 +203,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 45d6ea65ce4..f7598af121f 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 08321f1bf17..0b959100420 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;
@@ -228,6 +230,16 @@ public abstract class RuleBasedAuthorizationPluginBase
return false;
} else {
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 97a9677b69b..108b3f637f6 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -49,6 +49,7 @@ import java.util.Random;
import java.util.Set;
import java.util.function.Supplier;
import net.jcip.annotations.ThreadSafe;
+import org.apache.commons.lang3.StringUtils;
import org.apache.solr.api.ApiBag;
import org.apache.solr.api.V2HttpCall;
import org.apache.solr.client.api.util.SolrVersion;
@@ -154,7 +155,7 @@ public class HttpSolrCall {
this.requestType = RequestType.UNKNOWN;
this.userAgentSolrVersion = parseUserAgentSolrVersion();
this.span =
Optional.ofNullable(TraceUtils.getSpan(req)).orElse(Span.getInvalid());
- this.path = ServletUtils.getPathAfterContext(req);
+ normalizeAndSetPath(ServletUtils.getPathAfterContext(req));
req.setAttribute(HttpSolrCall.class.getName(), this);
// set a request timer which can be reused by requests if needed
@@ -163,6 +164,11 @@ public class HttpSolrCall {
req.setAttribute("org.apache.solr.CoreContainer", cores);
}
+ @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;
}
@@ -217,7 +223,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)) {
@@ -226,7 +232,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("");
@@ -255,14 +261,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);
if (action == REMOTEPROXY) {
- path = path.substring(idx);
+ normalizeAndSetPath(path.substring(idx));
return;
}
}