SOLR-13969: Clean up and document AuditEvent API (#1041)

This commit is contained in:
Jan Høydahl 2019-11-28 09:55:11 +01:00 committed by GitHub
parent cc4f3802ef
commit 9f78482295
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 142 additions and 18 deletions

View File

@ -152,6 +152,8 @@ Improvements
* SOLR-13961: When using partial/atomic updates to remove child documents, we now support setting to null or * SOLR-13961: When using partial/atomic updates to remove child documents, we now support setting to null or
an empty list as equivalent to the "remove" command. (Thomas Wöckinger) an empty list as equivalent to the "remove" command. (Thomas Wöckinger)
* SOLR-13969: Clean up and document AuditEvent API (janhoy)
Optimizations Optimizations
--------------------- ---------------------
(No changes) (No changes)

View File

@ -29,6 +29,7 @@ import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.servlet.ServletUtils; import org.apache.solr.servlet.ServletUtils;
@ -48,7 +49,7 @@ import static org.apache.solr.security.AuditEvent.EventType.ERROR;
*/ */
public class AuditEvent { public class AuditEvent {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private StringBuffer requestUrl; private String baseUrl;
private String nodeName; private String nodeName;
private String message; private String message;
private Level level; private Level level;
@ -69,10 +70,10 @@ public class AuditEvent {
private EventType eventType; private EventType eventType;
private AuthorizationResponse autResponse; private AuthorizationResponse autResponse;
private RequestType requestType; private RequestType requestType;
private double QTime = -1; private double qTime = -1;
private int status = -1; private int status = -1;
private Throwable exception; private Throwable exception;
/* Predefined event types. Custom types can be made through constructor */ /* Predefined event types. Custom types can be made through constructor */
public enum EventType { public enum EventType {
AUTHENTICATED("Authenticated", "User successfully authenticated", Level.INFO, -1), AUTHENTICATED("Authenticated", "User successfully authenticated", Level.INFO, -1),
@ -134,7 +135,7 @@ public class AuditEvent {
this.httpMethod = httpRequest.getMethod(); this.httpMethod = httpRequest.getMethod();
this.httpQueryString = httpRequest.getQueryString(); this.httpQueryString = httpRequest.getQueryString();
this.headers = getHeadersFromRequest(httpRequest); this.headers = getHeadersFromRequest(httpRequest);
this.requestUrl = httpRequest.getRequestURL(); this.baseUrl = httpRequest.getRequestURL().toString();
this.nodeName = MDC.get(ZkStateReader.NODE_NAME_PROP); this.nodeName = MDC.get(ZkStateReader.NODE_NAME_PROP);
SolrRequestParsers.parseQueryString(httpQueryString).forEach(sp -> { SolrRequestParsers.parseQueryString(httpQueryString).forEach(sp -> {
this.solrParams.put(sp.getKey(), Arrays.asList(sp.getValue())); this.solrParams.put(sp.getKey(), Arrays.asList(sp.getValue()));
@ -222,75 +223,135 @@ public class AuditEvent {
} }
} }
} }
/**
* The human readable message about this event
*/
public String getMessage() { public String getMessage() {
return message; return message;
} }
/**
* Level of this event. Can be INFO, WARN or ERROR
* @return {@link Level} enum
*/
public Level getLevel() { public Level getLevel() {
return level; return level;
} }
/**
* Date that the event happened
*/
public Date getDate() { public Date getDate() {
return date; return date;
} }
/**
* Username of logged in user, or null if no authenticated user
*/
public String getUsername() { public String getUsername() {
return username; return username;
} }
/**
* Session identifier
*/
public String getSession() { public String getSession() {
return session; return session;
} }
/**
* IP address of the client doing the request
*/
public String getClientIp() { public String getClientIp() {
return clientIp; return clientIp;
} }
/**
* A general purpose context map with potential extra information about the event
*/
public Map<String, Object> getContext() { public Map<String, Object> getContext() {
return context; return context;
} }
/**
* List of collection names involved in request
*/
public List<String> getCollections() { public List<String> getCollections() {
return collections; return collections;
} }
/**
* Identifies the resource being operated on. This is not the same as URL path.
* For queries the resource is relative to collection name, e.g. /select or /update.
* For other events the resource may be /api/node/health or /admin/collection
*/
public String getResource() { public String getResource() {
return resource; return resource;
} }
/**
* The HTTP method. E.g. GET, POST, PUT
*/
public String getHttpMethod() { public String getHttpMethod() {
return httpMethod; return httpMethod;
} }
/**
* Query part of URL or null if query part
*/
public String getHttpQueryString() { public String getHttpQueryString() {
return httpQueryString; return httpQueryString;
} }
/**
* EventType tells the outcome of the event such as REJECTED, UNAUTHORIZED or ERROR
* @return {@link EventType} enum
*/
public EventType getEventType() { public EventType getEventType() {
return eventType; return eventType;
} }
/**
* Host name of the Solr node logging the event
*/
public String getSolrHost() { public String getSolrHost() {
return solrHost; return solrHost;
} }
/**
* IP address of the Solr node logging the event
*/
public String getSolrIp() { public String getSolrIp() {
return solrIp; return solrIp;
} }
/**
* Port number of the Solr node logging the event
*/
public int getSolrPort() { public int getSolrPort() {
return solrPort; return solrPort;
} }
/**
* Map of all HTTP request headers belonging to the request
*/
public Map<String, String> getHeaders() { public Map<String, String> getHeaders() {
return headers; return headers;
} }
/**
* Map of all Solr request parameters attached to the request. Pulled from url
*/
public Map<String, List<String>> getSolrParams() { public Map<String, List<String>> getSolrParams() {
return solrParams; return solrParams;
} }
/**
* Gets first value of a certain Solr request parameter
* @param key name of request parameter to retrieve
* @return String value of the first value, regardless of number of valies
*/
public String getSolrParamAsString(String key) { public String getSolrParamAsString(String key) {
List<String> v = getSolrParams().get(key); List<String> v = getSolrParams().get(key);
if (v != null && v.size() > 0) { if (v != null && v.size() > 0) {
@ -298,42 +359,84 @@ public class AuditEvent {
} }
return null; return null;
} }
/**
* The authorization response object from authorization plugin, or null authz has not happened
*/
public AuthorizationResponse getAutResponse() { public AuthorizationResponse getAutResponse() {
return autResponse; return autResponse;
} }
/**
* Node name of Solr node, on the internal format host:port_context, e.g. 10.0.0.1:8983_solr
*/
public String getNodeName() { public String getNodeName() {
return nodeName; return nodeName;
} }
/**
* Determines the type of request. Can be ADMIN, SEARCH, UPDATE, STREAMING, UNKNOWN
* @return {@link RequestType} enum
*/
public RequestType getRequestType() { public RequestType getRequestType() {
return requestType; return requestType;
} }
/**
* HTTP status code of event, i.e. 200 = OK, 401 = unauthorized
*/
public int getStatus() { public int getStatus() {
return status; return status;
} }
/**
* Request time in milliseconds for completed requests
*/
public double getQTime() { public double getQTime() {
return QTime; return qTime;
} }
/**
* In case of ERROR event, find the exception causing the error
*/
public Throwable getException() { public Throwable getException() {
return exception; return exception;
} }
/**
* Get baseUrl as StringBuffer for back compat with previous version
* @deprecated Please use {@link #getBaseUrl()} instead
* @return StringBuffer of the base url without query part
*/
@Deprecated
@JsonIgnore
public StringBuffer getRequestUrl() { public StringBuffer getRequestUrl() {
return requestUrl; return new StringBuffer(baseUrl);
}
/**
* Full URL of the original request. This is {@link #baseUrl} + "?" + {@link #httpQueryString}.
* Returns null if not set
*/
public String getUrl() {
if (baseUrl == null) return null;
return baseUrl + (httpQueryString != null ? "?" + httpQueryString : "");
}
/**
* First part of URL of the request, but not including request parameters, or null if not set
*/
public String getBaseUrl() {
return baseUrl;
} }
// Setters, builder style // Setters, builder style
public AuditEvent setRequestUrl(StringBuffer requestUrl) { public AuditEvent setBaseUrl(String baseUrl) {
this.requestUrl = requestUrl; this.baseUrl = baseUrl;
return this; return this;
} }
public AuditEvent setSession(String session) { public AuditEvent setSession(String session) {
this.session = session; this.session = session;
return this; return this;
@ -429,8 +532,8 @@ public class AuditEvent {
return this; return this;
} }
public AuditEvent setQTime(double QTime) { public AuditEvent setQTime(double qTime) {
this.QTime = QTime; this.qTime = qTime;
return this; return this;
} }

View File

@ -38,6 +38,13 @@ public class AuditLoggerPluginTest extends SolrTestCaseJ4 {
.setMessage("Anonymous") .setMessage("Anonymous")
.setResource("/collection1") .setResource("/collection1")
.setDate(SAMPLE_DATE); .setDate(SAMPLE_DATE);
protected static final AuditEvent EVENT_WITH_URL = new AuditEvent(AuditEvent.EventType.ANONYMOUS)
.setHttpMethod("GET")
.setMessage("Anonymous")
.setResource("/collection1")
.setBaseUrl("http://myserver/mypath")
.setHttpQueryString("a=b&c=d")
.setDate(SAMPLE_DATE);
protected static final AuditEvent EVENT_ANONYMOUS_REJECTED = new AuditEvent(AuditEvent.EventType.ANONYMOUS_REJECTED) protected static final AuditEvent EVENT_ANONYMOUS_REJECTED = new AuditEvent(AuditEvent.EventType.ANONYMOUS_REJECTED)
.setHttpMethod("GET") .setHttpMethod("GET")
.setMessage("Anonymous rejected") .setMessage("Anonymous rejected")
@ -194,6 +201,18 @@ public class AuditLoggerPluginTest extends SolrTestCaseJ4 {
plugin.formatter.formatEvent(EVENT_ANONYMOUS)); plugin.formatter.formatEvent(EVENT_ANONYMOUS));
assertEquals("{\"message\":\"Authenticated\",\"level\":\"INFO\",\"date\":" + SAMPLE_DATE.getTime() + ",\"username\":\"Jan\",\"solrParams\":{},\"solrPort\":0,\"resource\":\"/collection1\",\"httpMethod\":\"GET\",\"eventType\":\"AUTHENTICATED\",\"status\":-1,\"qtime\":-1.0}", assertEquals("{\"message\":\"Authenticated\",\"level\":\"INFO\",\"date\":" + SAMPLE_DATE.getTime() + ",\"username\":\"Jan\",\"solrParams\":{},\"solrPort\":0,\"resource\":\"/collection1\",\"httpMethod\":\"GET\",\"eventType\":\"AUTHENTICATED\",\"status\":-1,\"qtime\":-1.0}",
plugin.formatter.formatEvent(EVENT_AUTHENTICATED)); plugin.formatter.formatEvent(EVENT_AUTHENTICATED));
} }
@Test
public void getBaseUrl() {
assertEquals("http://myserver/mypath", EVENT_WITH_URL.getBaseUrl());
// Deprecated
assertEquals("http://myserver/mypath", EVENT_WITH_URL.getRequestUrl().toString());
}
@Test
public void getUrl() {
assertEquals("http://myserver/mypath?a=b&c=d",
EVENT_WITH_URL.getUrl());
}
} }