security: make control of logfile audit output consistent with index output

This change moves the logfile audit output from determining what to log based on the
logger level to a enum based configuration that is used by the index output.

A few notable changes were made:

* We alway log all the information we have except for the request body
* The request body is no longer logged by default for REST events; the user needs to
explicitly opt in as there could be sensitive data in the body
* Added a `realm_authentication_failed` event that separates overall authentication
failure from that of an individual realm

Original commit: elastic/x-pack-elasticsearch@343a2bcdd9
This commit is contained in:
jaymode 2016-09-02 13:37:30 -04:00
parent 89ce4ebb08
commit 7965608add
10 changed files with 663 additions and 794 deletions

View File

@ -3,7 +3,7 @@ appender.audit_rolling.name = audit_rolling
appender.audit_rolling.fileName = ${sys:es.logs}_access.log appender.audit_rolling.fileName = ${sys:es.logs}_access.log
appender.audit_rolling.layout.type = PatternLayout appender.audit_rolling.layout.type = PatternLayout
appender.audit_rolling.layout.pattern = [%d{ISO8601}] %m%n appender.audit_rolling.layout.pattern = [%d{ISO8601}] %m%n
appender.audit_rolling.filePattern = ${sys:es.logs}-%d{yyyy-MM-dd}.log appender.audit_rolling.filePattern = ${sys:es.logs}_access-%d{yyyy-MM-dd}.log
appender.audit_rolling.policies.type = Policies appender.audit_rolling.policies.type = Policies
appender.audit_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.audit_rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.audit_rolling.policies.time.interval = 1 appender.audit_rolling.policies.time.interval = 1

View File

@ -3,17 +3,18 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.xpack.security.audit.index; package org.elasticsearch.xpack.security.audit;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
public enum IndexAuditLevel { public enum AuditLevel {
ANONYMOUS_ACCESS_DENIED, ANONYMOUS_ACCESS_DENIED,
AUTHENTICATION_FAILED, AUTHENTICATION_FAILED,
REALM_AUTHENTICATION_FAILED,
ACCESS_GRANTED, ACCESS_GRANTED,
ACCESS_DENIED, ACCESS_DENIED,
TAMPERED_REQUEST, TAMPERED_REQUEST,
@ -23,13 +24,13 @@ public enum IndexAuditLevel {
RUN_AS_GRANTED, RUN_AS_GRANTED,
RUN_AS_DENIED; RUN_AS_DENIED;
static EnumSet<IndexAuditLevel> parse(List<String> levels) { static EnumSet<AuditLevel> parse(List<String> levels) {
EnumSet<IndexAuditLevel> enumSet = EnumSet.noneOf(IndexAuditLevel.class); EnumSet<AuditLevel> enumSet = EnumSet.noneOf(AuditLevel.class);
for (String level : levels) { for (String level : levels) {
String lowerCaseLevel = level.trim().toLowerCase(Locale.ROOT); String lowerCaseLevel = level.trim().toLowerCase(Locale.ROOT);
switch (lowerCaseLevel) { switch (lowerCaseLevel) {
case "_all": case "_all":
enumSet.addAll(Arrays.asList(IndexAuditLevel.values())); enumSet.addAll(Arrays.asList(AuditLevel.values()));
break; break;
case "anonymous_access_denied": case "anonymous_access_denied":
enumSet.add(ANONYMOUS_ACCESS_DENIED); enumSet.add(ANONYMOUS_ACCESS_DENIED);
@ -37,6 +38,9 @@ public enum IndexAuditLevel {
case "authentication_failed": case "authentication_failed":
enumSet.add(AUTHENTICATION_FAILED); enumSet.add(AUTHENTICATION_FAILED);
break; break;
case "realm_authentication_failed":
enumSet.add(REALM_AUTHENTICATION_FAILED);
break;
case "access_granted": case "access_granted":
enumSet.add(ACCESS_GRANTED); enumSet.add(ACCESS_GRANTED);
break; break;
@ -68,9 +72,9 @@ public enum IndexAuditLevel {
return enumSet; return enumSet;
} }
public static EnumSet<IndexAuditLevel> parse(List<String> includeLevels, List<String> excludeLevels) { public static EnumSet<AuditLevel> parse(List<String> includeLevels, List<String> excludeLevels) {
EnumSet<IndexAuditLevel> included = parse(includeLevels); EnumSet<AuditLevel> included = parse(includeLevels);
EnumSet<IndexAuditLevel> excluded = parse(excludeLevels); EnumSet<AuditLevel> excluded = parse(excludeLevels);
included.removeAll(excluded); included.removeAll(excluded);
return included; return included;
} }

View File

@ -51,6 +51,7 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationToken; import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege; import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege;
@ -85,19 +86,20 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function; import java.util.function.Function;
import static org.elasticsearch.xpack.security.Security.setting; import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.audit.AuditLevel.REALM_AUTHENTICATION_FAILED;
import static org.elasticsearch.xpack.security.audit.AuditUtil.indices; import static org.elasticsearch.xpack.security.audit.AuditUtil.indices;
import static org.elasticsearch.xpack.security.audit.AuditUtil.restRequestContent; import static org.elasticsearch.xpack.security.audit.AuditUtil.restRequestContent;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.ACCESS_DENIED; import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_DENIED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.ACCESS_GRANTED; import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_GRANTED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.ANONYMOUS_ACCESS_DENIED; import static org.elasticsearch.xpack.security.audit.AuditLevel.ANONYMOUS_ACCESS_DENIED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.AUTHENTICATION_FAILED; import static org.elasticsearch.xpack.security.audit.AuditLevel.AUTHENTICATION_FAILED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.CONNECTION_DENIED; import static org.elasticsearch.xpack.security.audit.AuditLevel.CONNECTION_DENIED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.CONNECTION_GRANTED; import static org.elasticsearch.xpack.security.audit.AuditLevel.CONNECTION_GRANTED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.RUN_AS_DENIED; import static org.elasticsearch.xpack.security.audit.AuditLevel.RUN_AS_DENIED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.RUN_AS_GRANTED; import static org.elasticsearch.xpack.security.audit.AuditLevel.RUN_AS_GRANTED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.SYSTEM_ACCESS_GRANTED; import static org.elasticsearch.xpack.security.audit.AuditLevel.SYSTEM_ACCESS_GRANTED;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.TAMPERED_REQUEST; import static org.elasticsearch.xpack.security.audit.AuditLevel.TAMPERED_REQUEST;
import static org.elasticsearch.xpack.security.audit.index.IndexAuditLevel.parse; import static org.elasticsearch.xpack.security.audit.AuditLevel.parse;
import static org.elasticsearch.xpack.security.audit.index.IndexNameResolver.resolve; import static org.elasticsearch.xpack.security.audit.index.IndexNameResolver.resolve;
/** /**
@ -105,27 +107,30 @@ import static org.elasticsearch.xpack.security.audit.index.IndexNameResolver.res
*/ */
public class IndexAuditTrail extends AbstractComponent implements AuditTrail, ClusterStateListener { public class IndexAuditTrail extends AbstractComponent implements AuditTrail, ClusterStateListener {
public static final int DEFAULT_BULK_SIZE = 1000;
public static final int MAX_BULK_SIZE = 10000;
public static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
public static final TimeValue DEFAULT_FLUSH_INTERVAL = TimeValue.timeValueSeconds(1);
public static final IndexNameResolver.Rollover DEFAULT_ROLLOVER = IndexNameResolver.Rollover.DAILY;
public static final String NAME = "index"; public static final String NAME = "index";
public static final String INDEX_NAME_PREFIX = ".security_audit_log"; public static final String INDEX_NAME_PREFIX = ".security_audit_log";
public static final String DOC_TYPE = "event"; public static final String DOC_TYPE = "event";
public static final Setting<IndexNameResolver.Rollover> ROLLOVER_SETTING = public static final String INDEX_TEMPLATE_NAME = "security_audit_log";
private static final int DEFAULT_BULK_SIZE = 1000;
private static final int MAX_BULK_SIZE = 10000;
private static final int DEFAULT_MAX_QUEUE_SIZE = 1000;
private static final TimeValue DEFAULT_FLUSH_INTERVAL = TimeValue.timeValueSeconds(1);
private static final IndexNameResolver.Rollover DEFAULT_ROLLOVER = IndexNameResolver.Rollover.DAILY;
private static final Setting<IndexNameResolver.Rollover> ROLLOVER_SETTING =
new Setting<>(setting("audit.index.rollover"), (s) -> DEFAULT_ROLLOVER.name(), new Setting<>(setting("audit.index.rollover"), (s) -> DEFAULT_ROLLOVER.name(),
s -> IndexNameResolver.Rollover.valueOf(s.toUpperCase(Locale.ENGLISH)), Property.NodeScope); s -> IndexNameResolver.Rollover.valueOf(s.toUpperCase(Locale.ENGLISH)), Property.NodeScope);
public static final Setting<Integer> QUEUE_SIZE_SETTING = private static final Setting<Integer> QUEUE_SIZE_SETTING =
Setting.intSetting(setting("audit.index.queue_max_size"), DEFAULT_MAX_QUEUE_SIZE, 1, Property.NodeScope); Setting.intSetting(setting("audit.index.queue_max_size"), DEFAULT_MAX_QUEUE_SIZE, 1, Property.NodeScope);
public static final String INDEX_TEMPLATE_NAME = "security_audit_log"; private static final String DEFAULT_CLIENT_NAME = "security-audit-client";
public static final String DEFAULT_CLIENT_NAME = "security-audit-client";
static final List<String> DEFAULT_EVENT_INCLUDES = Arrays.asList( private static final List<String> DEFAULT_EVENT_INCLUDES = Arrays.asList(
ACCESS_DENIED.toString(), ACCESS_DENIED.toString(),
ACCESS_GRANTED.toString(), ACCESS_GRANTED.toString(),
ANONYMOUS_ACCESS_DENIED.toString(), ANONYMOUS_ACCESS_DENIED.toString(),
AUTHENTICATION_FAILED.toString(), AUTHENTICATION_FAILED.toString(),
REALM_AUTHENTICATION_FAILED.toString(),
CONNECTION_DENIED.toString(), CONNECTION_DENIED.toString(),
CONNECTION_GRANTED.toString(), CONNECTION_GRANTED.toString(),
TAMPERED_REQUEST.toString(), TAMPERED_REQUEST.toString(),
@ -134,23 +139,24 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
); );
private static final String FORBIDDEN_INDEX_SETTING = "index.mapper.dynamic"; private static final String FORBIDDEN_INDEX_SETTING = "index.mapper.dynamic";
public static final Setting<Settings> INDEX_SETTINGS = private static final Setting<Settings> INDEX_SETTINGS =
Setting.groupSetting(setting("audit.index.settings.index."), Property.NodeScope); Setting.groupSetting(setting("audit.index.settings.index."), Property.NodeScope);
public static final Setting<List<String>> INCLUDE_EVENT_SETTINGS = private static final Setting<List<String>> INCLUDE_EVENT_SETTINGS =
Setting.listSetting(setting("audit.index.events.include"), DEFAULT_EVENT_INCLUDES, Function.identity(), Setting.listSetting(setting("audit.index.events.include"), DEFAULT_EVENT_INCLUDES, Function.identity(),
Property.NodeScope); Property.NodeScope);
public static final Setting<List<String>> EXCLUDE_EVENT_SETTINGS = private static final Setting<List<String>> EXCLUDE_EVENT_SETTINGS =
Setting.listSetting(setting("audit.index.events.exclude"), Collections.emptyList(), Setting.listSetting(setting("audit.index.events.exclude"), Collections.emptyList(),
Function.identity(), Property.NodeScope); Function.identity(), Property.NodeScope);
public static final Setting<Settings> REMOTE_CLIENT_SETTINGS = private static final Setting<Boolean> INCLUDE_REQUEST_BODY =
Setting.boolSetting(setting("audit.index.events.emit_request_body"), false, Property.NodeScope);
private static final Setting<Settings> REMOTE_CLIENT_SETTINGS =
Setting.groupSetting(setting("audit.index.client."), Property.NodeScope); Setting.groupSetting(setting("audit.index.client."), Property.NodeScope);
public static final Setting<Integer> BULK_SIZE_SETTING = private static final Setting<Integer> BULK_SIZE_SETTING =
Setting.intSetting(setting("audit.index.bulk_size"), DEFAULT_BULK_SIZE, 1, MAX_BULK_SIZE, Property.NodeScope); Setting.intSetting(setting("audit.index.bulk_size"), DEFAULT_BULK_SIZE, 1, MAX_BULK_SIZE, Property.NodeScope);
public static final Setting<TimeValue> FLUSH_TIMEOUT_SETTING = private static final Setting<TimeValue> FLUSH_TIMEOUT_SETTING =
Setting.timeSetting(setting("audit.index.flush_interval"), DEFAULT_FLUSH_INTERVAL, Setting.timeSetting(setting("audit.index.flush_interval"), DEFAULT_FLUSH_INTERVAL,
TimeValue.timeValueMillis(1L), Property.NodeScope); TimeValue.timeValueMillis(1L), Property.NodeScope);
private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED); private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED);
private final String nodeName; private final String nodeName;
private final Client client; private final Client client;
@ -160,12 +166,13 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
private final Lock putMappingLock = new ReentrantLock(); private final Lock putMappingLock = new ReentrantLock();
private final ClusterService clusterService; private final ClusterService clusterService;
private final boolean indexToRemoteCluster; private final boolean indexToRemoteCluster;
private final EnumSet<AuditLevel> events;
private final IndexNameResolver.Rollover rollover;
private final boolean includeRequestBody;
private BulkProcessor bulkProcessor; private BulkProcessor bulkProcessor;
private IndexNameResolver.Rollover rollover;
private String nodeHostName; private String nodeHostName;
private String nodeHostAddress; private String nodeHostAddress;
private EnumSet<IndexAuditLevel> events;
@Override @Override
public String name() { public String name() {
@ -180,25 +187,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
this.queueConsumer = new QueueConsumer(EsExecutors.threadName(settings, "audit-queue-consumer")); this.queueConsumer = new QueueConsumer(EsExecutors.threadName(settings, "audit-queue-consumer"));
int maxQueueSize = QUEUE_SIZE_SETTING.get(settings); int maxQueueSize = QUEUE_SIZE_SETTING.get(settings);
this.eventQueue = createQueue(maxQueueSize); this.eventQueue = createQueue(maxQueueSize);
this.rollover = ROLLOVER_SETTING.get(settings);
// we have to initialize this here since we use rollover in determining if we can start... this.events = parse(INCLUDE_EVENT_SETTINGS.get(settings), EXCLUDE_EVENT_SETTINGS.get(settings));
rollover = ROLLOVER_SETTING.get(settings);
// we have to initialize the events here since we can receive events before starting...
List<String> includedEvents = INCLUDE_EVENT_SETTINGS.get(settings);
List<String> excludedEvents = EXCLUDE_EVENT_SETTINGS.get(settings);
try {
events = parse(includedEvents, excludedEvents);
} catch (IllegalArgumentException e) {
logger.warn(
(Supplier<?>) () -> new ParameterizedMessage(
"invalid event type specified, using default for audit index output. include events [{}], exclude events [{}]",
includedEvents,
excludedEvents),
e);
events = parse(DEFAULT_EVENT_INCLUDES, Collections.emptyList());
}
this.indexToRemoteCluster = REMOTE_CLIENT_SETTINGS.get(settings).names().size() > 0; this.indexToRemoteCluster = REMOTE_CLIENT_SETTINGS.get(settings).names().size() > 0;
this.includeRequestBody = INCLUDE_REQUEST_BODY.get(settings);
if (indexToRemoteCluster == false) { if (indexToRemoteCluster == false) {
// in the absence of client settings for remote indexing, fall back to the client that was passed in. // in the absence of client settings for remote indexing, fall back to the client that was passed in.
@ -391,7 +383,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
@Override @Override
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) { public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) { if (events.contains(REALM_AUTHENTICATION_FAILED)) {
if (XPackUser.is(token.principal()) == false) { if (XPackUser.is(token.principal()) == false) {
try { try {
enqueue(message("authentication_failed", action, token, realm, indices(message), message), "authentication_failed"); enqueue(message("authentication_failed", action, token, realm, indices(message), message), "authentication_failed");
@ -404,7 +396,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
@Override @Override
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) { public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
if (events.contains(AUTHENTICATION_FAILED)) { if (events.contains(REALM_AUTHENTICATION_FAILED)) {
if (XPackUser.is(token.principal()) == false) { if (XPackUser.is(token.principal()) == false) {
try { try {
enqueue(message("authentication_failed", null, token, realm, null, request), "authentication_failed"); enqueue(message("authentication_failed", null, token, realm, null, request), "authentication_failed");
@ -610,7 +602,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
if (indices != null) { if (indices != null) {
msg.builder.array(Field.INDICES, indices.toArray(Strings.EMPTY_ARRAY)); msg.builder.array(Field.INDICES, indices.toArray(Strings.EMPTY_ARRAY));
} }
if (includeRequestBody) {
msg.builder.field(Field.REQUEST_BODY, restRequestContent(request)); msg.builder.field(Field.REQUEST_BODY, restRequestContent(request));
}
msg.builder.field(Field.ORIGIN_TYPE, "rest"); msg.builder.field(Field.ORIGIN_TYPE, "rest");
SocketAddress address = request.getRemoteAddress(); SocketAddress address = request.getRemoteAddress();
if (address instanceof InetSocketAddress) { if (address instanceof InetSocketAddress) {
@ -630,7 +624,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
common("rest", type, msg.builder); common("rest", type, msg.builder);
msg.builder.field(Field.PRINCIPAL, user.principal()); msg.builder.field(Field.PRINCIPAL, user.principal());
if (includeRequestBody) {
msg.builder.field(Field.REQUEST_BODY, restRequestContent(request)); msg.builder.field(Field.REQUEST_BODY, restRequestContent(request));
}
msg.builder.field(Field.ORIGIN_TYPE, "rest"); msg.builder.field(Field.ORIGIN_TYPE, "rest");
SocketAddress address = request.getRemoteAddress(); SocketAddress address = request.getRemoteAddress();
if (address instanceof InetSocketAddress) { if (address instanceof InetSocketAddress) {
@ -905,6 +901,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
settings.add(FLUSH_TIMEOUT_SETTING); settings.add(FLUSH_TIMEOUT_SETTING);
settings.add(QUEUE_SIZE_SETTING); settings.add(QUEUE_SIZE_SETTING);
settings.add(REMOTE_CLIENT_SETTINGS); settings.add(REMOTE_CLIENT_SETTINGS);
settings.add(INCLUDE_REQUEST_BODY);
} }
private class QueueConsumer extends Thread { private class QueueConsumer extends Thread {

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationToken; import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege; import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege;
@ -32,11 +33,27 @@ import org.elasticsearch.xpack.security.user.XPackUser;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.common.Strings.collectionToCommaDelimitedString; import static org.elasticsearch.common.Strings.collectionToCommaDelimitedString;
import static org.elasticsearch.xpack.security.Security.setting; import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_DENIED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_GRANTED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.ANONYMOUS_ACCESS_DENIED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.AUTHENTICATION_FAILED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.REALM_AUTHENTICATION_FAILED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.CONNECTION_DENIED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.CONNECTION_GRANTED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.RUN_AS_DENIED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.RUN_AS_GRANTED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.SYSTEM_ACCESS_GRANTED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.TAMPERED_REQUEST;
import static org.elasticsearch.xpack.security.audit.AuditLevel.parse;
import static org.elasticsearch.xpack.security.audit.AuditUtil.indices; import static org.elasticsearch.xpack.security.audit.AuditUtil.indices;
import static org.elasticsearch.xpack.security.audit.AuditUtil.restRequestContent; import static org.elasticsearch.xpack.security.audit.AuditUtil.restRequestContent;
@ -52,10 +69,28 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail {
Setting.boolSetting(setting("audit.logfile.prefix.emit_node_host_name"), false, Property.NodeScope); Setting.boolSetting(setting("audit.logfile.prefix.emit_node_host_name"), false, Property.NodeScope);
public static final Setting<Boolean> NODE_NAME_SETTING = public static final Setting<Boolean> NODE_NAME_SETTING =
Setting.boolSetting(setting("audit.logfile.prefix.emit_node_name"), true, Property.NodeScope); Setting.boolSetting(setting("audit.logfile.prefix.emit_node_name"), true, Property.NodeScope);
private static final List<String> DEFAULT_EVENT_INCLUDES = Arrays.asList(
ACCESS_DENIED.toString(),
ACCESS_GRANTED.toString(),
ANONYMOUS_ACCESS_DENIED.toString(),
AUTHENTICATION_FAILED.toString(),
CONNECTION_DENIED.toString(),
TAMPERED_REQUEST.toString(),
RUN_AS_DENIED.toString(),
RUN_AS_GRANTED.toString()
);
private static final Setting<List<String>> INCLUDE_EVENT_SETTINGS =
Setting.listSetting(setting("audit.logfile.events.include"), DEFAULT_EVENT_INCLUDES, Function.identity(), Property.NodeScope);
private static final Setting<List<String>> EXCLUDE_EVENT_SETTINGS =
Setting.listSetting(setting("audit.logfile.events.exclude"), Collections.emptyList(), Function.identity(), Property.NodeScope);
private static final Setting<Boolean> INCLUDE_REQUEST_BODY =
Setting.boolSetting(setting("audit.logfile.events.emit_request_body"), false, Property.NodeScope);
private final Logger logger; private final Logger logger;
private final ClusterService clusterService; private final ClusterService clusterService;
private final ThreadContext threadContext; private final ThreadContext threadContext;
private final EnumSet<AuditLevel> events;
private final boolean includeRequestBody;
private String prefix; private String prefix;
@ -73,6 +108,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail {
this.logger = logger; this.logger = logger;
this.clusterService = clusterService; this.clusterService = clusterService;
this.threadContext = threadContext; this.threadContext = threadContext;
this.events = parse(INCLUDE_EVENT_SETTINGS.get(settings), EXCLUDE_EVENT_SETTINGS.get(settings));
this.includeRequestBody = INCLUDE_REQUEST_BODY.get(settings);
} }
private String getPrefix() { private String getPrefix() {
@ -84,115 +121,98 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail {
@Override @Override
public void anonymousAccessDenied(String action, TransportMessage message) { public void anonymousAccessDenied(String action, TransportMessage message) {
if (events.contains(ANONYMOUS_ACCESS_DENIED)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices, originAttributes(message, clusterService.localNode(), threadContext), action, indices,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else { } else {
logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [anonymous_access_denied]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, message.getClass().getSimpleName()); originAttributes(message, clusterService.localNode(), threadContext), action, message.getClass().getSimpleName());
} else {
logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action);
} }
} }
} }
@Override @Override
public void anonymousAccessDenied(RestRequest request) { public void anonymousAccessDenied(RestRequest request) {
if (logger.isDebugEnabled()) { if (events.contains(ANONYMOUS_ACCESS_DENIED)) {
logger.debug("{}[rest] [anonymous_access_denied]\t{}, uri=[{}], request_body=[{}]", getPrefix(), if (includeRequestBody) {
logger.info("{}[rest] [anonymous_access_denied]\t{}, uri=[{}], request_body=[{}]", getPrefix(),
hostAttributes(request), request.uri(), restRequestContent(request)); hostAttributes(request), request.uri(), restRequestContent(request));
} else { } else {
logger.warn("{}[rest] [anonymous_access_denied]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri()); logger.info("{}[rest] [anonymous_access_denied]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri());
}
} }
} }
@Override @Override
public void authenticationFailed(AuthenticationToken token, String action, TransportMessage message) { public void authenticationFailed(AuthenticationToken token, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}], request=[{}]",
logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}], request=[{}]",
getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), token.principal(), getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), token.principal(),
action, indices, message.getClass().getSimpleName()); action, indices, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), token.principal(), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), token.principal(), action, originAttributes(message, clusterService.localNode(), threadContext), token.principal(), action,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else {
logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), token.principal(), action);
} }
} }
} }
@Override @Override
public void authenticationFailed(RestRequest request) { public void authenticationFailed(RestRequest request) {
if (logger.isDebugEnabled()) { if (events.contains(AUTHENTICATION_FAILED)) {
logger.debug("{}[rest] [authentication_failed]\t{}, uri=[{}], request_body=[{}]", getPrefix(), hostAttributes(request), if (includeRequestBody) {
logger.info("{}[rest] [authentication_failed]\t{}, uri=[{}], request_body=[{}]", getPrefix(), hostAttributes(request),
request.uri(), restRequestContent(request)); request.uri(), restRequestContent(request));
} else { } else {
logger.error("{}[rest] [authentication_failed]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri()); logger.info("{}[rest] [authentication_failed]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri());
}
} }
} }
@Override @Override
public void authenticationFailed(String action, TransportMessage message) { public void authenticationFailed(String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices, originAttributes(message, clusterService.localNode(), threadContext), action, indices,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [authentication_failed]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, message.getClass().getSimpleName()); originAttributes(message, clusterService.localNode(), threadContext), action, message.getClass().getSimpleName());
} else {
logger.error("{}[transport] [authentication_failed]\t{}, action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action);
} }
} }
} }
@Override @Override
public void authenticationFailed(AuthenticationToken token, RestRequest request) { public void authenticationFailed(AuthenticationToken token, RestRequest request) {
if (logger.isDebugEnabled()) { if (events.contains(AUTHENTICATION_FAILED)) {
logger.debug("{}[rest] [authentication_failed]\t{}, principal=[{}], uri=[{}], request_body=[{}]", getPrefix(), if (includeRequestBody) {
logger.info("{}[rest] [authentication_failed]\t{}, principal=[{}], uri=[{}], request_body=[{}]", getPrefix(),
hostAttributes(request), token.principal(), request.uri(), restRequestContent(request)); hostAttributes(request), token.principal(), request.uri(), restRequestContent(request));
} else { } else {
logger.error("{}[rest] [authentication_failed]\t{}, principal=[{}], uri=[{}]", getPrefix(), hostAttributes(request), logger.info("{}[rest] [authentication_failed]\t{}, principal=[{}], uri=[{}]", getPrefix(), hostAttributes(request),
token.principal(), request.uri()); token.principal(), request.uri());
} }
} }
}
@Override @Override
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) { public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) {
if (logger.isTraceEnabled()) { if (events.contains(REALM_AUTHENTICATION_FAILED)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], indices=[{}], " + logger.info("{}[transport] [realm_authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], indices=[{}], " +
"request=[{}]", getPrefix(), realm, originAttributes(message, clusterService.localNode(), threadContext), "request=[{}]", getPrefix(), realm, originAttributes(message, clusterService.localNode(), threadContext),
token.principal(), action, indices, message.getClass().getSimpleName()); token.principal(), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], request=[{}]", logger.info("{}[transport] [realm_authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], request=[{}]",
getPrefix(), realm, originAttributes(message, clusterService.localNode(), threadContext), token.principal(), getPrefix(), realm, originAttributes(message, clusterService.localNode(), threadContext), token.principal(),
action, message.getClass().getSimpleName()); action, message.getClass().getSimpleName());
} }
@ -201,185 +221,142 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail {
@Override @Override
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) { public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
if (logger.isTraceEnabled()) { if (events.contains(REALM_AUTHENTICATION_FAILED)) {
logger.trace("{}[rest] [authentication_failed]\trealm=[{}], {}, principal=[{}], uri=[{}], request_body=[{}]", getPrefix(), if (includeRequestBody) {
realm, hostAttributes(request), token.principal(), request.uri(), restRequestContent(request)); logger.info("{}[rest] [realm_authentication_failed]\trealm=[{}], {}, principal=[{}], uri=[{}], request_body=[{}]",
getPrefix(), realm, hostAttributes(request), token.principal(), request.uri(), restRequestContent(request));
} else {
logger.info("{}[rest] [realm_authentication_failed]\trealm=[{}], {}, principal=[{}], uri=[{}]", getPrefix(),
realm, hostAttributes(request), token.principal(), request.uri());
}
} }
} }
@Override @Override
public void accessGranted(User user, String action, TransportMessage message) { public void accessGranted(User user, String action, TransportMessage message) {
final boolean isSystem = (SystemUser.is(user) && SystemPrivilege.INSTANCE.predicate().test(action)) || XPackUser.is(user);
final boolean logSystemAccessGranted = isSystem && events.contains(SYSTEM_ACCESS_GRANTED);
final boolean shouldLog = logSystemAccessGranted || (isSystem == false && events.contains(ACCESS_GRANTED));
if (shouldLog) {
String indices = indicesString(message); String indices = indicesString(message);
// special treatment for internal system actions - only log on trace
if ((SystemUser.is(user) && SystemPrivilege.INSTANCE.predicate().test(action)) || XPackUser.is(user)) {
if (logger.isTraceEnabled()) {
if (indices != null) { if (indices != null) {
logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(), logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices, originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else { } else {
logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", getPrefix(), logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, originAttributes(message, clusterService.localNode(), threadContext), principal(user), action,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} }
} }
return;
}
if (indices != null) {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices,
message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action,
message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action);
}
}
} }
@Override @Override
public void accessDenied(User user, String action, TransportMessage message) { public void accessDenied(User user, String action, TransportMessage message) {
if (events.contains(ACCESS_DENIED)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices, originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [access_denied]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action, originAttributes(message, clusterService.localNode(), threadContext), principal(user), action,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else {
logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), principal(user), action);
} }
} }
} }
@Override @Override
public void tamperedRequest(RestRequest request) { public void tamperedRequest(RestRequest request) {
if (logger.isDebugEnabled()) { if (events.contains(TAMPERED_REQUEST)) {
logger.debug("{}[rest] [tampered_request]\t{}, uri=[{}], request_body=[{}]", getPrefix(), hostAttributes(request), if (includeRequestBody) {
logger.info("{}[rest] [tampered_request]\t{}, uri=[{}], request_body=[{}]", getPrefix(), hostAttributes(request),
request.uri(), restRequestContent(request)); request.uri(), restRequestContent(request));
} else { } else {
logger.error("{}[rest] [tampered_request]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri()); logger.info("{}[rest] [tampered_request]\t{}, uri=[{}]", getPrefix(), hostAttributes(request), request.uri());
}
} }
} }
@Override @Override
public void tamperedRequest(String action, TransportMessage message) { public void tamperedRequest(String action, TransportMessage message) {
if (events.contains(TAMPERED_REQUEST)) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices, originAttributes(message, clusterService.localNode(), threadContext), action, indices,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [tampered_request]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], request=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action, originAttributes(message, clusterService.localNode(), threadContext), action,
message.getClass().getSimpleName()); message.getClass().getSimpleName());
} else {
logger.error("{}[transport] [tampered_request]\t{}, action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), action);
} }
} }
} }
@Override @Override
public void tamperedRequest(User user, String action, TransportMessage request) { public void tamperedRequest(User user, String action, TransportMessage request) {
if (events.contains(TAMPERED_REQUEST)) {
String indices = indicesString(request); String indices = indicesString(request);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { logger.info("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}], request=[{}]", getPrefix(),
originAttributes(request, clusterService.localNode(), threadContext), principal(user), action, indices, originAttributes(request, clusterService.localNode(), threadContext), principal(user), action, indices,
request.getClass().getSimpleName()); request.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}]", getPrefix(), logger.info("{}[transport] [tampered_request]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(request, clusterService.localNode(), threadContext), principal(user), action, indices);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], request=[{}]", getPrefix(),
originAttributes(request, clusterService.localNode(), threadContext), principal(user), action, originAttributes(request, clusterService.localNode(), threadContext), principal(user), action,
request.getClass().getSimpleName()); request.getClass().getSimpleName());
} else {
logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}]", getPrefix(),
originAttributes(request, clusterService.localNode(), threadContext), principal(user), action);
} }
} }
} }
@Override @Override
public void connectionGranted(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) { public void connectionGranted(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
if (logger.isTraceEnabled()) { if (events.contains(CONNECTION_GRANTED)) {
logger.trace("{}[ip_filter] [connection_granted]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", getPrefix(), logger.info("{}[ip_filter] [connection_granted]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", getPrefix(),
NetworkAddress.format(inetAddress), profile, rule); NetworkAddress.format(inetAddress), profile, rule);
} }
} }
@Override @Override
public void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) { public void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
logger.error("{}[ip_filter] [connection_denied]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", getPrefix(), if (events.contains(CONNECTION_DENIED)) {
logger.info("{}[ip_filter] [connection_denied]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", getPrefix(),
NetworkAddress.format(inetAddress), profile, rule); NetworkAddress.format(inetAddress), profile, rule);
} }
}
@Override @Override
public void runAsGranted(User user, String action, TransportMessage message) { public void runAsGranted(User user, String action, TransportMessage message) {
if (logger.isDebugEnabled()) { if (events.contains(RUN_AS_GRANTED)) {
logger.debug("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]",
getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), user.principal(), getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), user.principal(),
user.runAs().principal(), action, message.getClass().getSimpleName()); user.runAs().principal(), action, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), user.principal(),
user.runAs().principal(), action);
} }
} }
@Override @Override
public void runAsDenied(User user, String action, TransportMessage message) { public void runAsDenied(User user, String action, TransportMessage message) {
if (logger.isDebugEnabled()) { if (events.contains(RUN_AS_DENIED)) {
logger.debug("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]",
getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), user.principal(), getPrefix(), originAttributes(message, clusterService.localNode(), threadContext), user.principal(),
user.runAs().principal(), action, message.getClass().getSimpleName()); user.runAs().principal(), action, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", getPrefix(),
originAttributes(message, clusterService.localNode(), threadContext), user.principal(),
user.runAs().principal(), action);
} }
} }
@Override @Override
public void runAsDenied(User user, RestRequest request) { public void runAsDenied(User user, RestRequest request) {
if (logger.isDebugEnabled()) { if (events.contains(RUN_AS_DENIED)) {
logger.debug("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}], request_body=[{}]", getPrefix(), if (includeRequestBody) {
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}], request_body=[{}]", getPrefix(),
hostAttributes(request), user.principal(), request.uri(), restRequestContent(request)); hostAttributes(request), user.principal(), request.uri(), restRequestContent(request));
} else { } else {
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], uri=[{}]", getPrefix(), logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}]", getPrefix(),
hostAttributes(request), user.principal(), request.uri()); hostAttributes(request), user.principal(), request.uri());
} }
} }
}
private static String hostAttributes(RestRequest request) { private static String hostAttributes(RestRequest request) {
String formattedAddress; String formattedAddress;
@ -465,5 +442,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail {
settings.add(HOST_ADDRESS_SETTING); settings.add(HOST_ADDRESS_SETTING);
settings.add(HOST_NAME_SETTING); settings.add(HOST_NAME_SETTING);
settings.add(NODE_NAME_SETTING); settings.add(NODE_NAME_SETTING);
settings.add(INCLUDE_EVENT_SETTINGS);
settings.add(EXCLUDE_EVENT_SETTINGS);
settings.add(INCLUDE_REQUEST_BODY);
} }
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.audit;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Locale;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
public class AuditLevelTests extends ESTestCase {
public void testAllIndexAuditLevel() {
EnumSet<AuditLevel> enumSet = AuditLevel.parse(Collections.singletonList("_all"));
AuditLevel[] levels = AuditLevel.values();
assertThat(enumSet.size(), is(levels.length));
for (AuditLevel level : levels) {
assertThat(enumSet.contains(level), is(true));
}
}
public void testExcludeHasPreference() {
EnumSet<AuditLevel> enumSet = AuditLevel.parse(Collections.singletonList("_all"), Collections.singletonList("_all"));
assertThat(enumSet.size(), is(0));
}
public void testExcludeHasPreferenceSingle() {
String excluded = randomFrom(AuditLevel.values()).toString().toLowerCase(Locale.ROOT);
EnumSet<AuditLevel> enumSet = AuditLevel.parse(Collections.singletonList("_all"), Collections.singletonList(excluded));
EnumSet<AuditLevel> expected = EnumSet.allOf(AuditLevel.class);
expected.remove(AuditLevel.valueOf(excluded.toUpperCase(Locale.ROOT)));
assertThat(enumSet, equalTo(expected));
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.audit.index;
import org.elasticsearch.test.ESTestCase;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Locale;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
public class IndexAuditLevelTests extends ESTestCase {
public void testAllIndexAuditLevel() {
EnumSet<IndexAuditLevel> enumSet = IndexAuditLevel.parse(Collections.singletonList("_all"));
IndexAuditLevel[] levels = IndexAuditLevel.values();
assertThat(enumSet.size(), is(levels.length));
for (IndexAuditLevel level : levels) {
assertThat(enumSet.contains(level), is(true));
}
}
public void testExcludeHasPreference() {
EnumSet<IndexAuditLevel> enumSet = IndexAuditLevel.parse(Collections.singletonList("_all"), Collections.singletonList("_all"));
assertThat(enumSet.size(), is(0));
}
public void testExcludeHasPreferenceSingle() {
String excluded = randomFrom(IndexAuditLevel.values()).toString().toLowerCase(Locale.ROOT);
EnumSet<IndexAuditLevel> enumSet = IndexAuditLevel.parse(Collections.singletonList("_all"), Collections.singletonList(excluded));
EnumSet<IndexAuditLevel> expected = EnumSet.allOf(IndexAuditLevel.class);
expected.remove(IndexAuditLevel.valueOf(excluded.toUpperCase(Locale.ROOT)));
assertThat(enumSet, equalTo(expected));
}
}

View File

@ -113,11 +113,6 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
TransportMessage message = mock(TransportMessage.class); TransportMessage message = mock(TransportMessage.class);
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
// with realm
auditTrail.authenticationFailed(randomAsciiOfLengthBetween(2, 10), token, "_action", message);
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
// without realm // without realm
auditTrail.authenticationFailed(token, "_action", message); auditTrail.authenticationFailed(token, "_action", message);
assertThat(messageEnqueued.get(), is(false)); assertThat(messageEnqueued.get(), is(false));
@ -136,11 +131,6 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
RestRequest restRequest = mock(RestRequest.class); RestRequest restRequest = mock(RestRequest.class);
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
// with realm
auditTrail.authenticationFailed(randomAsciiOfLengthBetween(2, 10), token, restRequest);
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
// without the realm // without the realm
auditTrail.authenticationFailed(token, restRequest); auditTrail.authenticationFailed(token, restRequest);
assertThat(messageEnqueued.get(), is(false)); assertThat(messageEnqueued.get(), is(false));
@ -154,6 +144,31 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
verifyZeroInteractions(token, restRequest); verifyZeroInteractions(token, restRequest);
} }
public void testAuthenticationFailedRealmMutedTransport() {
createAuditTrail(new String[] { "realm_authentication_failed" });
TransportMessage message = mock(TransportMessage.class);
AuthenticationToken token = mock(AuthenticationToken.class);
// with realm
auditTrail.authenticationFailed(randomAsciiOfLengthBetween(2, 10), token, "_action", message);
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(token, message);
}
public void testAuthenticationFailedRealmMutedRest() {
createAuditTrail(new String[]{"realm_authentication_failed"});
RestRequest restRequest = mock(RestRequest.class);
AuthenticationToken token = mock(AuthenticationToken.class);
// with realm
auditTrail.authenticationFailed(randomAsciiOfLengthBetween(2, 10), token, restRequest);
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(token, restRequest);
}
public void testAccessGrantedMuted() { public void testAccessGrantedMuted() {
createAuditTrail(new String[] { "access_granted" }); createAuditTrail(new String[] { "access_granted" });
TransportMessage message = mock(TransportMessage.class); TransportMessage message = mock(TransportMessage.class);

View File

@ -96,6 +96,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
private int numShards; private int numShards;
private int numReplicas; private int numReplicas;
private ThreadPool threadPool; private ThreadPool threadPool;
private boolean includeRequestBody;
@BeforeClass @BeforeClass
public static void configureBeforeClass() { public static void configureBeforeClass() {
@ -241,6 +242,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
Settings.Builder builder = Settings.builder(); Settings.Builder builder = Settings.builder();
builder.put(levelSettings(includes, excludes)); builder.put(levelSettings(includes, excludes));
builder.put(commonSettings(rollover)); builder.put(commonSettings(rollover));
builder.put("xpack.security.audit.index.events.emit_request_body", includeRequestBody);
return builder.build(); return builder.build();
} }
@ -256,6 +258,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
rollover = randomFrom(HOURLY, DAILY, WEEKLY, MONTHLY); rollover = randomFrom(HOURLY, DAILY, WEEKLY, MONTHLY);
numReplicas = numberOfReplicas(); numReplicas = numberOfReplicas();
numShards = numberOfShards(); numShards = numberOfShards();
includeRequestBody = randomBoolean();
Settings.Builder builder = Settings.builder(); Settings.Builder builder = Settings.builder();
if (remoteIndexing) { if (remoteIndexing) {
builder.put(remoteSettings); builder.put(remoteSettings);
@ -314,7 +317,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertThat(NetworkAddress.format(InetAddress.getLoopbackAddress()), equalTo(sourceMap.get("origin_address"))); assertThat(NetworkAddress.format(InetAddress.getLoopbackAddress()), equalTo(sourceMap.get("origin_address")));
assertThat("_uri", equalTo(sourceMap.get("uri"))); assertThat("_uri", equalTo(sourceMap.get("uri")));
assertThat(sourceMap.get("origin_type"), is("rest")); assertThat(sourceMap.get("origin_type"), is("rest"));
assertThat(sourceMap.get("request_body"), notNullValue()); assertRequestBody(sourceMap);
} }
public void testAuthenticationFailedTransport() throws Exception { public void testAuthenticationFailedTransport() throws Exception {
@ -373,7 +376,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address"))); assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address")));
assertThat("_uri", equalTo(sourceMap.get("uri"))); assertThat("_uri", equalTo(sourceMap.get("uri")));
assertThat(sourceMap.get("origin_type"), is("rest")); assertThat(sourceMap.get("origin_type"), is("rest"));
assertThat(sourceMap.get("request_body"), notNullValue()); assertRequestBody(sourceMap);
} }
public void testAuthenticationFailedRestNoToken() throws Exception { public void testAuthenticationFailedRestNoToken() throws Exception {
@ -388,7 +391,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address"))); assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address")));
assertThat("_uri", equalTo(sourceMap.get("uri"))); assertThat("_uri", equalTo(sourceMap.get("uri")));
assertThat(sourceMap.get("origin_type"), is("rest")); assertThat(sourceMap.get("origin_type"), is("rest"));
assertThat(sourceMap.get("request_body"), notNullValue()); assertRequestBody(sourceMap);
} }
public void testAuthenticationFailedTransportRealm() throws Exception { public void testAuthenticationFailedTransportRealm() throws Exception {
@ -429,7 +432,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertThat("_uri", equalTo(sourceMap.get("uri"))); assertThat("_uri", equalTo(sourceMap.get("uri")));
assertEquals("_realm", sourceMap.get("realm")); assertEquals("_realm", sourceMap.get("realm"));
assertThat(sourceMap.get("origin_type"), is("rest")); assertThat(sourceMap.get("origin_type"), is("rest"));
assertThat(sourceMap.get("request_body"), notNullValue()); assertRequestBody(sourceMap);
} }
public void testAccessGranted() throws Exception { public void testAccessGranted() throws Exception {
@ -520,7 +523,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address"))); assertThat("127.0.0.1", equalTo(sourceMap.get("origin_address")));
assertThat("_uri", equalTo(sourceMap.get("uri"))); assertThat("_uri", equalTo(sourceMap.get("uri")));
assertThat(sourceMap.get("origin_type"), is("rest")); assertThat(sourceMap.get("origin_type"), is("rest"));
assertThat(sourceMap.get("request_body"), notNullValue()); assertRequestBody(sourceMap);
} }
public void testTamperedRequest() throws Exception { public void testTamperedRequest() throws Exception {
@ -638,6 +641,13 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals(type, sourceMap.get("event_type")); assertEquals(type, sourceMap.get("event_type"));
} }
private void assertRequestBody(Map<String, Object> sourceMap) {
if (includeRequestBody) {
assertThat(sourceMap.get("request_body"), notNullValue());
} else {
assertThat(sourceMap.get("request_body"), nullValue());
}
}
private static class LocalHostMockMessage extends TransportMessage { private static class LocalHostMockMessage extends TransportMessage {
LocalHostMockMessage() { LocalHostMockMessage() {
remoteAddress(new LocalTransportAddress("local_host")); remoteAddress(new LocalTransportAddress("local_host"));

View File

@ -14,7 +14,6 @@ import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.filter.RegexFilter; import org.apache.logging.log4j.core.filter.RegexFilter;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.logging.TestLoggers; import org.elasticsearch.common.logging.TestLoggers;

View File

@ -105,53 +105,45 @@ public class LoggingAuditTrailTests extends ESTestCase {
private DiscoveryNode localNode; private DiscoveryNode localNode;
private ClusterService clusterService; private ClusterService clusterService;
private ThreadContext threadContext; private ThreadContext threadContext;
private boolean includeRequestBody;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
includeRequestBody = randomBoolean();
settings = Settings.builder() settings = Settings.builder()
.put("xpack.security.audit.logfile.prefix.emit_node_host_address", randomBoolean()) .put("xpack.security.audit.logfile.prefix.emit_node_host_address", randomBoolean())
.put("xpack.security.audit.logfile.prefix.emit_node_host_name", randomBoolean()) .put("xpack.security.audit.logfile.prefix.emit_node_host_name", randomBoolean())
.put("xpack.security.audit.logfile.prefix.emit_node_name", randomBoolean()) .put("xpack.security.audit.logfile.prefix.emit_node_name", randomBoolean())
.put("xpack.security.audit.logfile.events.emit_request_body", includeRequestBody)
.build(); .build();
localNode = mock(DiscoveryNode.class); localNode = mock(DiscoveryNode.class);
when(localNode.getHostAddress()).thenReturn(LocalTransportAddress.buildUnique().toString()); when(localNode.getHostAddress()).thenReturn(LocalTransportAddress.buildUnique().toString());
clusterService = mock(ClusterService.class); clusterService = mock(ClusterService.class);
when(clusterService.localNode()).thenReturn(localNode); when(clusterService.localNode()).thenReturn(localNode);
prefix = LoggingAuditTrail.resolvePrefix(settings, localNode); prefix = LoggingAuditTrail.resolvePrefix(settings, localNode);
threadContext = new ThreadContext(Settings.EMPTY);
} }
public void testAnonymousAccessDeniedTransport() throws Exception { public void testAnonymousAccessDeniedTransport() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, clusterService.localNode(), threadContext); String origins = LoggingAuditTrail.originAttributes(message, clusterService.localNode(), threadContext);
auditTrail.anonymousAccessDenied("_action", message); auditTrail.anonymousAccessDenied("_action", message);
switch (level.toString()) {
case "ERROR":
assertEmptyLog(logger);
break;
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.WARN, prefix + "[transport] [anonymous_access_denied]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [anonymous_access_denied]\t" + origins +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.WARN, prefix + "[transport] [anonymous_access_denied]\t" + origins + ", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [anonymous_access_denied]\t" + origins +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [anonymous_access_denied]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [anonymous_access_denied]\t" + origins +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "anonymous_access_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.anonymousAccessDenied("_action", message);
assertEmptyLog(logger);
} }
public void testAnonymousAccessDeniedRest() throws Exception { public void testAnonymousAccessDeniedRest() throws Exception {
@ -160,207 +152,172 @@ public class LoggingAuditTrailTests extends ESTestCase {
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.anonymousAccessDenied(request); auditTrail.anonymousAccessDenied(request);
switch (level.toString()) { if (includeRequestBody) {
case "ERROR": assertMsg(logger, Level.INFO, prefix + "[rest] [anonymous_access_denied]\torigin_address=[" +
assertEmptyLog(logger);
break;
case "WARN":
case "INFO":
assertMsg(logger, Level.WARN, prefix + "[rest] [anonymous_access_denied]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[rest] [anonymous_access_denied]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]"); NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[rest] [anonymous_access_denied]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
} }
}
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "anonymous_access_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.anonymousAccessDenied(request);
assertEmptyLog(logger);
} }
public void testAuthenticationFailed() throws Exception { public void testAuthenticationFailed() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);; String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);;
auditTrail.authenticationFailed(new MockToken(), "_action", message); auditTrail.authenticationFailed(new MockToken(), "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.ERROR, prefix + "[transport] [authentication_failed]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [authentication_failed]\t" + origins +
", principal=[_principal], action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.ERROR, prefix + "[transport] [authentication_failed]\t" + origins +
", principal=[_principal], action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [authentication_failed]\t" + origins +
", principal=[_principal], action=[_action], indices=[" + indices(message) + ", principal=[_principal], action=[_action], indices=[" + indices(message) +
"], request=[MockIndicesRequest]"); "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [authentication_failed]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [authentication_failed]\t" + origins +
", principal=[_principal], action=[_action], request=[MockMessage]"); ", principal=[_principal], action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed(new MockToken(), "_action", message);
assertEmptyLog(logger);
} }
public void testAuthenticationFailedNoToken() throws Exception { public void testAuthenticationFailedNoToken() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);; String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);;
auditTrail.authenticationFailed("_action", message); auditTrail.authenticationFailed("_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.ERROR, prefix + "[transport] [authentication_failed]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [authentication_failed]\t" + origins +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.ERROR, prefix + "[transport] [authentication_failed]\t" + origins +
", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [authentication_failed]\t" + origins +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [authentication_failed]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [authentication_failed]\t" + origins +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed("_action", message);
assertEmptyLog(logger);
} }
public void testAuthenticationFailedRest() throws Exception { public void testAuthenticationFailedRest() throws Exception {
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
Logger logger = CapturingLogger.newCapturingLogger(level); Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed(new MockToken(), request); auditTrail.authenticationFailed(new MockToken(), request);
switch (level.toString()) { if (includeRequestBody) {
case "ERROR": assertMsg(logger, Level.INFO, prefix + "[rest] [authentication_failed]\torigin_address=[" +
case "WARN":
case "INFO":
assertMsg(logger, Level.ERROR, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri], request_body=[" + NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri], request_body=[" +
expectedMessage + "]"); expectedMessage + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri]");
} }
}
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed(new MockToken(), request);
assertEmptyLog(logger);
} }
public void testAuthenticationFailedRestNoToken() throws Exception { public void testAuthenticationFailedRestNoToken() throws Exception {
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
Logger logger = CapturingLogger.newCapturingLogger(level); Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed(request); auditTrail.authenticationFailed(request);
switch (level.toString()) { if (includeRequestBody) {
case "ERROR": assertMsg(logger, Level.INFO, prefix + "[rest] [authentication_failed]\torigin_address=[" +
case "WARN":
case "INFO":
assertMsg(logger, Level.ERROR, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]"); NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[rest] [authentication_failed]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
} }
}
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed(request);
assertEmptyLog(logger);
} }
public void testAuthenticationFailedRealm() throws Exception { public void testAuthenticationFailedRealm() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);; String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message); auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
case "DEBUG":
assertEmptyLog(logger); assertEmptyLog(logger);
break;
case "TRACE": // test enabled
settings =
Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "realm_authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message);
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.TRACE, prefix + "[transport] [authentication_failed]\trealm=[_realm], " + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [realm_authentication_failed]\trealm=[_realm], " + origins +
", principal=[_principal], action=[_action], indices=[" + indices(message) + "], " + ", principal=[_principal], action=[_action], indices=[" + indices(message) + "], " +
"request=[MockIndicesRequest]"); "request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.TRACE, prefix + "[transport] [authentication_failed]\trealm=[_realm], " + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [realm_authentication_failed]\trealm=[_realm], " + origins +
", principal=[_principal], action=[_action], request=[MockMessage]"); ", principal=[_principal], action=[_action], request=[MockMessage]");
} }
} }
}
}
public void testAuthenticationFailedRealmRest() throws Exception { public void testAuthenticationFailedRealmRest() throws Exception {
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
Logger logger = CapturingLogger.newCapturingLogger(level); Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed("_realm", new MockToken(), request); auditTrail.authenticationFailed("_realm", new MockToken(), request);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
case "DEBUG":
assertEmptyLog(logger); assertEmptyLog(logger);
break;
case "TRACE": // test enabled
assertMsg(logger, Level.TRACE, prefix + "[rest] [authentication_failed]\trealm=[_realm], origin_address=[" + settings =
Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "realm_authentication_failed").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.authenticationFailed("_realm", new MockToken(), request);
if (includeRequestBody) {
assertMsg(logger, Level.INFO, prefix + "[rest] [realm_authentication_failed]\trealm=[_realm], origin_address=[" +
NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri], request_body=[" + NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri], request_body=[" +
expectedMessage + "]"); expectedMessage + "]");
} } else {
assertMsg(logger, Level.INFO, prefix + "[rest] [realm_authentication_failed]\trealm=[_realm], origin_address=[" +
NetworkAddress.format(address) + "], principal=[_principal], uri=[_uri]");
} }
} }
public void testAccessGranted() throws Exception { public void testAccessGranted() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
@ -374,65 +331,46 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessGranted(user, "_action", message); auditTrail.accessGranted(user, "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
assertEmptyLog(logger);
break;
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "_action", message);
assertEmptyLog(logger);
} }
public void testAccessGrantedInternalSystemAction() throws Exception { public void testAccessGrantedInternalSystemAction() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message); auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
case "DEBUG":
assertEmptyLog(logger); assertEmptyLog(logger);
break;
case "TRACE": // test enabled
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "system_access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message);
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.TRACE, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal() SystemUser.INSTANCE.principal()
+ "], action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); + "], action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.TRACE, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal() + "], action=[internal:_action], request=[MockMessage]"); SystemUser.INSTANCE.principal() + "], action=[internal:_action], request=[MockMessage]");
} }
} }
}
}
public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exception { public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
@ -446,37 +384,24 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessGranted(user, "internal:_action", message); auditTrail.accessGranted(user, "internal:_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
assertEmptyLog(logger);
break;
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action], request=[MockMessage]"); ", action=[internal:_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "internal:_action", message);
assertEmptyLog(logger);
} }
public void testAccessDenied() throws Exception { public void testAccessDenied() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
@ -490,29 +415,20 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessDenied(user, "_action", message); auditTrail.accessDenied(user, "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.ERROR, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.ERROR, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessDenied(user, "_action", message);
assertEmptyLog(logger);
} }
public void testTamperedRequestRest() throws Exception { public void testTamperedRequestRest() throws Exception {
@ -521,58 +437,42 @@ public class LoggingAuditTrailTests extends ESTestCase {
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.tamperedRequest(request); auditTrail.tamperedRequest(request);
switch (level.toString()) { if (includeRequestBody) {
case "ERROR": assertMsg(logger, Level.INFO, prefix + "[rest] [tampered_request]\torigin_address=[" +
case "WARN":
case "INFO":
assertMsg(logger, Level.ERROR, prefix + "[rest] [tampered_request]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[rest] [tampered_request]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]"); NetworkAddress.format(address) + "], uri=[_uri], request_body=[" + expectedMessage + "]");
} else {
assertMsg(logger, Level.INFO, prefix + "[rest] [tampered_request]\torigin_address=[" +
NetworkAddress.format(address) + "], uri=[_uri]");
} }
}
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "tampered_request").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.tamperedRequest(request);
assertEmptyLog(logger);
} }
public void testTamperedRequest() throws Exception { public void testTamperedRequest() throws Exception {
String action = "_action"; String action = "_action";
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
Logger logger = CapturingLogger.newCapturingLogger(level); Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.tamperedRequest(action, message); auditTrail.tamperedRequest(action, message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.ERROR, prefix + "[transport] [tampered_request]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [tampered_request]\t" + origins +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.ERROR, prefix + "[transport] [tampered_request]\t" + origins + ", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [tampered_request]\t" + origins +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [tampered_request]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [tampered_request]\t" + origins +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
} }
public void testTamperedRequestWithUser() throws Exception { public void testTamperedRequestWithUser() throws Exception {
@ -585,137 +485,100 @@ public class LoggingAuditTrailTests extends ESTestCase {
user = new User("_username", new String[]{"r1"}); user = new User("_username", new String[]{"r1"});
} }
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
Logger logger = CapturingLogger.newCapturingLogger(level); Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.tamperedRequest(user, action, message); auditTrail.tamperedRequest(user, action, message);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
if (message instanceof IndicesRequest) { if (message instanceof IndicesRequest) {
assertMsg(logger, Level.ERROR, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "]");
} else {
assertMsg(logger, Level.ERROR, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo +
", action=[_action]");
}
break;
case "DEBUG":
case "TRACE":
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]"); ", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else { } else {
assertMsg(logger, Level.DEBUG, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo + assertMsg(logger, Level.INFO, prefix + "[transport] [tampered_request]\t" + origins + ", " + userInfo +
", action=[_action], request=[MockMessage]"); ", action=[_action], request=[MockMessage]");
} }
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "tampered_request").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.tamperedRequest(user, action, message);
assertEmptyLog(logger);
} }
public void testConnectionDenied() throws Exception { public void testConnectionDenied() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
InetAddress inetAddress = InetAddress.getLoopbackAddress(); InetAddress inetAddress = InetAddress.getLoopbackAddress();
SecurityIpFilterRule rule = new SecurityIpFilterRule(false, "_all"); SecurityIpFilterRule rule = new SecurityIpFilterRule(false, "_all");
auditTrail.connectionDenied(inetAddress, "default", rule); auditTrail.connectionDenied(inetAddress, "default", rule);
switch (level.toString()) { assertMsg(logger, Level.INFO, String.format(Locale.ROOT, prefix +
case "ERROR":
assertMsg(logger, Level.ERROR, String.format(Locale.ROOT, prefix +
"[ip_filter] [connection_denied]\torigin_address=[%s], transport_profile=[%s], rule=[deny %s]", "[ip_filter] [connection_denied]\torigin_address=[%s], transport_profile=[%s], rule=[deny %s]",
NetworkAddress.format(inetAddress), "default", "_all")); NetworkAddress.format(inetAddress), "default", "_all"));
break;
case "WARN": // test disabled
case "INFO": CapturingLogger.output(logger.getName(), Level.INFO).clear();
case "DEBUG": settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "connection_denied").build();
case "TRACE": auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
} auditTrail.connectionDenied(inetAddress, "default", rule);
} assertEmptyLog(logger);
} }
public void testConnectionGranted() throws Exception { public void testConnectionGranted() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
InetAddress inetAddress = InetAddress.getLoopbackAddress(); InetAddress inetAddress = InetAddress.getLoopbackAddress();
SecurityIpFilterRule rule = IPFilter.DEFAULT_PROFILE_ACCEPT_ALL; SecurityIpFilterRule rule = IPFilter.DEFAULT_PROFILE_ACCEPT_ALL;
auditTrail.connectionGranted(inetAddress, "default", rule); auditTrail.connectionGranted(inetAddress, "default", rule);
switch (level.toString()) {
case "ERROR":
case "WARN":
case "INFO":
case "DEBUG":
assertEmptyLog(logger); assertEmptyLog(logger);
break;
case "TRACE": // test enabled
assertMsg(logger, Level.TRACE, String.format(Locale.ROOT, prefix + "[ip_filter] " + CapturingLogger.output(logger.getName(), Level.INFO).clear();
"[connection_granted]\torigin_address=[%s], transport_profile=[default], rule=[allow default:accept_all]", settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "connection_granted").build();
NetworkAddress.format(inetAddress))); auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
} auditTrail.connectionGranted(inetAddress, "default", rule);
} assertMsg(logger, Level.INFO, String.format(Locale.ROOT, prefix + "[ip_filter] [connection_granted]\torigin_address=[%s], " +
"transport_profile=[default], rule=[allow default:accept_all]", NetworkAddress.format(inetAddress)));
} }
public void testRunAsGranted() throws Exception { public void testRunAsGranted() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = new MockMessage(threadContext); TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"}));
auditTrail.runAsGranted(user, "_action", message); auditTrail.runAsGranted(user, "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
assertEmptyLog(logger);
break;
case "INFO":
assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_granted]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_granted]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[transport] [run_as_granted]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]"); ", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]");
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsGranted(user, "_action", message);
assertEmptyLog(logger);
} }
public void testRunAsDenied() throws Exception { public void testRunAsDenied() throws Exception {
for (Level level : Level.values()) { Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
threadContext = new ThreadContext(Settings.EMPTY);
Logger logger = CapturingLogger.newCapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = new MockMessage(threadContext); TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext); String origins = LoggingAuditTrail.originAttributes(message, localNode, threadContext);
User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"}));
auditTrail.runAsDenied(user, "_action", message); auditTrail.runAsDenied(user, "_action", message);
switch (level.toString()) {
case "ERROR":
case "WARN":
assertEmptyLog(logger);
break;
case "INFO":
assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_denied]\t" + origins + assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_denied]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action]");
break;
case "DEBUG":
case "TRACE":
assertMsg(logger, Level.DEBUG, prefix + "[transport] [run_as_denied]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]"); ", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]");
}
} // test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsDenied(user, "_action", message);
assertEmptyLog(logger);
} }
public void testOriginAttributes() throws Exception { public void testOriginAttributes() throws Exception {
threadContext = new ThreadContext(Settings.EMPTY);
MockMessage message = new MockMessage(threadContext); MockMessage message = new MockMessage(threadContext);
String text = LoggingAuditTrail.originAttributes(message, localNode, threadContext);; String text = LoggingAuditTrail.originAttributes(message, localNode, threadContext);;
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext); InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);