This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git
The following commit(s) were added to refs/heads/main by this push:
new ab42b64 feat(config): HTTP Basic Authentication credentials (builds
on #89) (#152)
ab42b64 is described below
commit ab42b64da26b1320e1826737c6300e040a6e02e1
Author: Aditya Parikh <[email protected]>
AuthorDate: Mon Jun 15 12:34:33 2026 -0400
feat(config): HTTP Basic Authentication credentials (builds on #89) (#152)
* feat(config): support HTTP Basic Authentication credentials
Add optional `solr.username` / `solr.password` configuration properties
(also bound from the `SOLR_USERNAME` / `SOLR_PASSWORD` environment
variables) that, when both are set, are applied to every SolrJ request
via `HttpJdkSolrClient.Builder#withBasicAuthCredentials`. When either
value is missing or the username is blank, the client is built without
credentials so existing unauthenticated deployments are unaffected.
Documents the new variables in the Development and Architecture guides
and adds `SolrConfigAuthTest` covering:
- no credentials attached when both values are missing,
- no credentials attached when only one value is provided (or the
username is blank), and
- credentials applied when both values are provided.
The existing `SolrConfigUrlNormalizationTest` is updated to the new
record constructor.
Co-authored-by: Claude <[email protected]>
Signed-off-by: Yunus Emre Korkmaz <[email protected]>
* refactor(config): reuse Spring StringUtils/ReflectionUtils in basic-auth
wiring
Review cleanup on top of the HTTP Basic Auth support from #89 (by
@dolphinium). No behavioural change to the feature.
- SolrConfig: replace the inline `username != null && !username.isEmpty()`
guard with Spring's `StringUtils.hasText`, matching the convention already
used in HttpSecurityConfiguration and SearchService.
- SolrConfigAuthTest: drop the hand-rolled superclass-walking `findField`
helper in favour of
`ReflectionUtils.findField`/`makeAccessible`/`getField`,
and tighten the over-defensive `equals(x) || equals("Basic " + x)`
assertion
to an exact `assertEquals` now that the stored format is known (SolrJ
stores
`"Basic " + Base64(user:pass)` in UTF-8).
./gradlew build passes (Spotless + NullAway + full test suite incl.
Testcontainers).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: adityamparikh <[email protected]>
---------
Signed-off-by: Yunus Emre Korkmaz <[email protected]>
Signed-off-by: adityamparikh <[email protected]>
Signed-off-by: Eric Pugh <[email protected]>
Co-authored-by: Yunus Emre Korkmaz <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Eric Pugh <[email protected]>
---
.../apache/solr/mcp/server/config/SolrConfig.java | 3 ++-
.../solr/mcp/server/config/SolrConfigAuthTest.java | 30 ++++++++--------------
2 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/src/main/java/org/apache/solr/mcp/server/config/SolrConfig.java
b/src/main/java/org/apache/solr/mcp/server/config/SolrConfig.java
index d0eb1da..ae0eae4 100644
--- a/src/main/java/org/apache/solr/mcp/server/config/SolrConfig.java
+++ b/src/main/java/org/apache/solr/mcp/server/config/SolrConfig.java
@@ -24,6 +24,7 @@ import org.apache.solr.client.solrj.request.XMLRequestWriter;
import
org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
/**
* Spring Configuration class for Apache Solr client setup and connection
@@ -208,7 +209,7 @@ public class SolrConfig {
// are provided so existing unauthenticated deployments are
unaffected.
String username = properties.username();
String password = properties.password();
- if (username != null && !username.isEmpty() && password !=
null) {
+ if (StringUtils.hasText(username) && password != null) {
builder.withBasicAuthCredentials(username, password);
}
diff --git
a/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
b/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
index 8a49ded..8dd5740 100644
--- a/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
@@ -16,13 +16,14 @@
*/
package org.apache.solr.mcp.server.config;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.HttpJdkSolrClient;
@@ -31,6 +32,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
+import org.springframework.util.ReflectionUtils;
/**
* Unit tests for the optional HTTP Basic Authentication wiring performed by
@@ -62,10 +64,9 @@ class SolrConfigAuthTest {
@Test
void credentialsAppliedWhenBothProvided() throws Exception {
String header = authorizationHeaderFor("alice", "s3cret");
- assertNotNull(header);
- String expected =
Base64.getEncoder().encodeToString("alice:s3cret".getBytes());
- assertTrue(header.equals(expected) || header.equals("Basic " +
expected),
- "Expected Basic auth payload for alice:s3cret,
got: " + header);
+ String expected = "Basic "
+ +
Base64.getEncoder().encodeToString("alice:s3cret".getBytes(StandardCharsets.UTF_8));
+ assertEquals(expected, header);
}
private @org.jspecify.annotations.Nullable String
authorizationHeaderFor(
@@ -76,21 +77,10 @@ class SolrConfigAuthTest {
SolrConfig config = new SolrConfig();
try (SolrClient client = config.solrClient(properties, new
JsonResponseParser(objectMapper))) {
HttpJdkSolrClient httpClient =
assertInstanceOf(HttpJdkSolrClient.class, client);
- Field field = findField(httpClient.getClass(),
"basicAuthAuthorizationStr");
- field.setAccessible(true);
- return (String) field.get(httpClient);
+ Field field =
ReflectionUtils.findField(httpClient.getClass(), "basicAuthAuthorizationStr");
+ assertNotNull(field, "SolrJ field
'basicAuthAuthorizationStr' not found");
+ ReflectionUtils.makeAccessible(field);
+ return (String) ReflectionUtils.getField(field,
httpClient);
}
}
-
- private static Field findField(Class<?> type, String name) throws
NoSuchFieldException {
- Class<?> current = type;
- while (current != null) {
- try {
- return current.getDeclaredField(name);
- } catch (NoSuchFieldException ignored) {
- current = current.getSuperclass();
- }
- }
- throw new NoSuchFieldException(name);
- }
}