mirror of
https://github.com/apache/lucene.git
synced 2025-02-10 12:05:36 +00:00
SOLR-13905 Make findRequestType in AuditEvent more robust (#1014)
(cherry picked from commit e45c5ce9b9e70650f119976b8b2d91b3c760cb48)
This commit is contained in:
parent
4b37fb0c8f
commit
29e172f6e2
@ -75,6 +75,8 @@ Improvements
|
||||
* SOLR-13907: In the Cloud/tree section of the Admin UI, fix metadata panel and force an horizontal scrollbar for the tree
|
||||
(Richard Goodman via Tomás Fernández Löbbe)
|
||||
|
||||
* SOLR-13905: Make findRequestType in AuditEvent more robust (janhoy)
|
||||
|
||||
Optimizations
|
||||
---------------------
|
||||
(No changes)
|
||||
|
@ -131,7 +131,6 @@ public class AuditEvent {
|
||||
this.solrPort = httpRequest.getLocalPort();
|
||||
this.solrIp = httpRequest.getLocalAddr();
|
||||
this.clientIp = httpRequest.getRemoteAddr();
|
||||
this.resource = ServletUtils.getPathAfterContext(httpRequest);
|
||||
this.httpMethod = httpRequest.getMethod();
|
||||
this.httpQueryString = httpRequest.getQueryString();
|
||||
this.headers = getHeadersFromRequest(httpRequest);
|
||||
@ -141,6 +140,7 @@ public class AuditEvent {
|
||||
this.solrParams.put(sp.getKey(), Arrays.asList(sp.getValue()));
|
||||
});
|
||||
|
||||
setResource(ServletUtils.getPathAfterContext(httpRequest));
|
||||
setRequestType(findRequestType());
|
||||
|
||||
if (exception != null) setException(exception);
|
||||
@ -167,7 +167,7 @@ public class AuditEvent {
|
||||
this(eventType, httpRequest);
|
||||
this.collections = authorizationContext.getCollectionRequests()
|
||||
.stream().map(r -> r.collectionName).collect(Collectors.toList());
|
||||
this.resource = authorizationContext.getResource();
|
||||
setResource(authorizationContext.getResource());
|
||||
this.requestType = RequestType.convertType(authorizationContext.getRequestType());
|
||||
authorizationContext.getParams().forEach(p -> {
|
||||
this.solrParams.put(p.getKey(), Arrays.asList(p.getValue()));
|
||||
@ -380,7 +380,7 @@ public class AuditEvent {
|
||||
}
|
||||
|
||||
public AuditEvent setResource(String resource) {
|
||||
this.resource = resource;
|
||||
this.resource = normalizeResourcePath(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -452,30 +452,35 @@ public class AuditEvent {
|
||||
}
|
||||
|
||||
private RequestType findRequestType() {
|
||||
if (ADMIN_PATH_REGEXES.stream().map(Pattern::compile)
|
||||
.anyMatch(p -> p.matcher(resource).matches())) return RequestType.ADMIN;
|
||||
if (SEARCH_PATH_REGEXES.stream().map(Pattern::compile)
|
||||
.anyMatch(p -> p.matcher(resource).matches())) return RequestType.SEARCH;
|
||||
if (INDEXING_PATH_REGEXES.stream().map(Pattern::compile)
|
||||
.anyMatch(p -> p.matcher(resource).matches())) return RequestType.UPDATE;
|
||||
if (STREAMING_PATH_REGEXES.stream().map(Pattern::compile)
|
||||
.anyMatch(p -> p.matcher(resource).matches())) return RequestType.STREAMING;
|
||||
if (resource == null) return RequestType.UNKNOWN;
|
||||
if (SEARCH_PATH_PATTERNS.stream().anyMatch(p -> p.matcher(resource).matches())) return RequestType.SEARCH;
|
||||
if (INDEXING_PATH_PATTERNS.stream().anyMatch(p -> p.matcher(resource).matches())) return RequestType.UPDATE;
|
||||
if (STREAMING_PATH_PATTERNS.stream().anyMatch(p -> p.matcher(resource).matches())) return RequestType.STREAMING;
|
||||
if (ADMIN_PATH_PATTERNS.stream().anyMatch(p -> p.matcher(resource).matches())) return RequestType.ADMIN;
|
||||
return RequestType.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
protected String normalizeResourcePath(String resourcePath) {
|
||||
if (resourcePath == null) return "";
|
||||
return resourcePath.replaceFirst("^/____v2", "/api");
|
||||
}
|
||||
|
||||
private static final List<String> ADMIN_PATH_REGEXES = Arrays.asList(
|
||||
"^/admin/.*",
|
||||
"^/(____v2|api)/(c|collections)$",
|
||||
"^/(____v2|api)/(c|collections)/[^/]+/config$",
|
||||
"^/(____v2|api)/(c|collections)/[^/]+/schema$",
|
||||
"^/(____v2|api)/(c|collections)/[^/]+/shards.*",
|
||||
"^/(____v2|api)/cores.*$",
|
||||
"^/(____v2|api)/node$",
|
||||
"^/(____v2|api)/cluster$");
|
||||
"^/api/(c|collections)$",
|
||||
"^/api/(c|collections)/[^/]+/config$",
|
||||
"^/api/(c|collections)/[^/]+/schema$",
|
||||
"^/api/(c|collections)/[^/]+/shards.*",
|
||||
"^/api/cores.*$",
|
||||
"^/api/node.*$",
|
||||
"^/api/cluster.*$");
|
||||
|
||||
private static final List<String> STREAMING_PATH_REGEXES = Collections.singletonList(".*/stream.*");
|
||||
|
||||
private static final List<String> INDEXING_PATH_REGEXES = Collections.singletonList(".*/update.*");
|
||||
|
||||
private static final List<String> SEARCH_PATH_REGEXES = Arrays.asList(".*/select.*", ".*/query.*");
|
||||
|
||||
private static final List<Pattern> ADMIN_PATH_PATTERNS = ADMIN_PATH_REGEXES.stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
private static final List<Pattern> STREAMING_PATH_PATTERNS = STREAMING_PATH_REGEXES.stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
private static final List<Pattern> INDEXING_PATH_PATTERNS = INDEXING_PATH_REGEXES.stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
private static final List<Pattern> SEARCH_PATH_PATTERNS = SEARCH_PATH_REGEXES.stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
}
|
||||
|
@ -17,11 +17,13 @@
|
||||
package org.apache.solr.security;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -38,6 +40,7 @@ import com.codahale.metrics.Timer;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.lucene.util.TestUtil;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
@ -216,6 +219,17 @@ public class AuditLoggerIntegrationTest extends SolrCloudAuthTestCase {
|
||||
assertAuditEvent(events.get(2), ERROR,"/select", SEARCH, null, 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalAdminPathError() throws Exception {
|
||||
setupCluster(false, null, false);
|
||||
String baseUrl = testHarness.get().cluster.getJettySolrRunner(0).getBaseUrl().toString();
|
||||
expectThrows(FileNotFoundException.class, () -> {
|
||||
IOUtils.toString(new URL(baseUrl.replace("/solr", "") + "/api/node/foo"), StandardCharsets.UTF_8);
|
||||
});
|
||||
final List<AuditEvent> events = testHarness.get().receiver.waitForAuditEvents(1);
|
||||
assertAuditEvent(events.get(0), ERROR, "/api/node/foo", ADMIN, null, 404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authValid() throws Exception {
|
||||
setupCluster(false, null, true);
|
||||
|
@ -91,6 +91,18 @@ public class AuditLoggerPluginTest extends SolrTestCaseJ4 {
|
||||
.setDate(SAMPLE_DATE)
|
||||
.setCollections(Collections.singletonList("streamcoll"))
|
||||
.setResource("/stream");
|
||||
protected static final AuditEvent EVENT_HEALTH_API = new AuditEvent(AuditEvent.EventType.COMPLETED)
|
||||
.setUsername("Jan")
|
||||
.setHttpMethod("GET")
|
||||
.setMessage("Healthy")
|
||||
.setDate(SAMPLE_DATE)
|
||||
.setResource("/api/node/health");
|
||||
protected static final AuditEvent EVENT_HEALTH_V2 = new AuditEvent(AuditEvent.EventType.COMPLETED)
|
||||
.setUsername("Jan")
|
||||
.setHttpMethod("GET")
|
||||
.setMessage("Healthy")
|
||||
.setDate(SAMPLE_DATE)
|
||||
.setResource("/____v2/node/health");
|
||||
|
||||
private MockAuditLoggerPlugin plugin;
|
||||
private HashMap<String, Object> config;
|
||||
@ -134,6 +146,7 @@ public class AuditLoggerPluginTest extends SolrTestCaseJ4 {
|
||||
assertFalse(plugin.shouldLog(EVENT_ANONYMOUS.getEventType()));
|
||||
assertFalse(plugin.shouldLog(EVENT_AUTHENTICATED.getEventType()));
|
||||
assertFalse(plugin.shouldLog(EVENT_AUTHORIZED.getEventType()));
|
||||
assertFalse(plugin.shouldLog(EVENT_AUTHORIZED.getEventType()));
|
||||
}
|
||||
|
||||
@Test(expected = SolrException.class)
|
||||
@ -167,7 +180,14 @@ public class AuditLoggerPluginTest extends SolrTestCaseJ4 {
|
||||
assertEquals(1, plugin.typeCounts.getOrDefault("REJECTED", new AtomicInteger()).get());
|
||||
assertEquals(2, plugin.events.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void v2ApiPath() {
|
||||
assertEquals("/api/node/health", EVENT_HEALTH_API.getResource());
|
||||
// /____v2/ is mapped to /api/
|
||||
assertEquals("/api/node/health", EVENT_HEALTH_V2.getResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonEventFormatter() {
|
||||
assertEquals("{\"message\":\"Anonymous\",\"level\":\"INFO\",\"date\":" + SAMPLE_DATE.getTime() + ",\"solrParams\":{},\"solrPort\":0,\"resource\":\"/collection1\",\"httpMethod\":\"GET\",\"eventType\":\"ANONYMOUS\",\"status\":-1,\"qtime\":-1.0}",
|
||||
|
Loading…
x
Reference in New Issue
Block a user