Update audit trail filter policy settings (elastic/x-pack-elasticsearch#3984)

Audit trail filter policies can now be updated by the cluster update
settings API. Previously, policies were static inside the conf file.
This is helpful because, in practice, coming up with a reasonable
policy set is an iterative process, adding and changing policies to
shave off yet another pesky audit event.

Original commit: elastic/x-pack-elasticsearch@e8a670c427
This commit is contained in:
Albert Zaharovits 2018-03-17 11:30:11 +02:00 committed by GitHub
parent f1c83820f7
commit 891013a17b
4 changed files with 354 additions and 75 deletions

View File

@ -12,6 +12,7 @@ import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.network.NetworkAddress;
@ -39,10 +40,10 @@ import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
@ -112,7 +113,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
private final EnumSet<AuditLevel> events;
private final boolean includeRequestBody;
// protected for testing
protected final Predicate<AuditEventMetaInfo> filterPolicyPredicate;
final EventFilterPolicyRegistry eventFilterPolicyRegistry;
private final ThreadContext threadContext;
volatile LocalNodeInfo localNodeInfo;
@ -132,14 +133,38 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
this.includeRequestBody = INCLUDE_REQUEST_BODY.get(settings);
this.threadContext = threadContext;
this.localNodeInfo = new LocalNodeInfo(settings, null);
this.filterPolicyPredicate = new EventFilterPolicyRegistry(settings).ignorePredicate();
this.eventFilterPolicyRegistry = new EventFilterPolicyRegistry(settings);
clusterService.addListener(this);
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_PRINCIPALS, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings))
.changePrincipalsFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_REALMS, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings))
.changeRealmsFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_ROLES, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings))
.changeRolesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_INDICES, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings))
.changeIndicesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
}
@Override
public void authenticationSuccess(String realm, User user, RestRequest request) {
if (events.contains(AUTHENTICATION_SUCCESS) && filterPolicyPredicate
.test(new AuditEventMetaInfo(Optional.of(user), Optional.of(realm), Optional.empty(), Optional.empty())) == false) {
if (events.contains(AUTHENTICATION_SUCCESS) && (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.of(realm), Optional.empty(), Optional.empty())) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [authentication_success]\t{}, realm=[{}], uri=[{}], params=[{}], request_body=[{}]",
localNodeInfo.prefix, principal(user), realm, request.uri(), request.params(), restRequestContent(request));
@ -154,7 +179,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void authenticationSuccess(String realm, User user, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_SUCCESS)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.of(realm), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -174,7 +199,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void anonymousAccessDenied(String action, TransportMessage message) {
if (events.contains(ANONYMOUS_ACCESS_DENIED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}], request=[{}]",
@ -190,7 +216,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void anonymousAccessDenied(RestRequest request) {
if (events.contains(ANONYMOUS_ACCESS_DENIED) && filterPolicyPredicate.test(AuditEventMetaInfo.EMPTY) == false) {
if (events.contains(ANONYMOUS_ACCESS_DENIED)
&& (eventFilterPolicyRegistry.ignorePredicate().test(AuditEventMetaInfo.EMPTY) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [anonymous_access_denied]\t{}, uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), request.uri(), restRequestContent(request));
@ -205,7 +232,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void authenticationFailed(AuthenticationToken token, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}], request=[{}]",
@ -222,7 +250,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void authenticationFailed(RestRequest request) {
if (events.contains(AUTHENTICATION_FAILED) && filterPolicyPredicate.test(AuditEventMetaInfo.EMPTY) == false) {
if (events.contains(AUTHENTICATION_FAILED)
&& (eventFilterPolicyRegistry.ignorePredicate().test(AuditEventMetaInfo.EMPTY) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [authentication_failed]\t{}, uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), request.uri(), restRequestContent(request));
@ -236,7 +265,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void authenticationFailed(String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}], request=[{}]", localNodeInfo.prefix,
@ -253,7 +283,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void authenticationFailed(AuthenticationToken token, RestRequest request) {
if (events.contains(AUTHENTICATION_FAILED)
&& filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), Optional.empty())) == false) {
&& (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), Optional.empty())) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [authentication_failed]\t{}, principal=[{}], uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), token.principal(), request.uri(), restRequestContent(request));
@ -268,7 +299,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) {
if (events.contains(REALM_AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info(
@ -287,8 +319,9 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
if (events.contains(REALM_AUTHENTICATION_FAILED) && filterPolicyPredicate
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), Optional.empty())) == false) {
if (events.contains(REALM_AUTHENTICATION_FAILED)
&& (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), Optional.empty())) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [realm_authentication_failed]\trealm=[{}], {}, principal=[{}], uri=[{}], request_body=[{}]",
localNodeInfo.prefix, realm, hostAttributes(request), token.principal(), request.uri(),
@ -303,9 +336,9 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || (isSystem == false && events.contains(ACCESS_GRANTED))) {
if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || ((isSystem == false) && events.contains(ACCESS_GRANTED))) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -326,7 +359,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -345,7 +378,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void tamperedRequest(RestRequest request) {
if (events.contains(TAMPERED_REQUEST) && filterPolicyPredicate.test(AuditEventMetaInfo.EMPTY) == false) {
if (events.contains(TAMPERED_REQUEST) && (eventFilterPolicyRegistry.ignorePredicate().test(AuditEventMetaInfo.EMPTY) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [tampered_request]\t{}, uri=[{}], request_body=[{}]", localNodeInfo.prefix, hostAttributes(request),
request.uri(), restRequestContent(request));
@ -359,7 +392,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void tamperedRequest(String action, TransportMessage message) {
if (events.contains(TAMPERED_REQUEST)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}], request=[{}]", localNodeInfo.prefix,
@ -377,7 +411,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void tamperedRequest(User user, String action, TransportMessage request) {
if (events.contains(TAMPERED_REQUEST)) {
final Optional<String[]> indices = indices(request);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.empty(), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -395,7 +429,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void connectionGranted(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
if (events.contains(CONNECTION_GRANTED) && filterPolicyPredicate.test(AuditEventMetaInfo.EMPTY) == false) {
if (events.contains(CONNECTION_GRANTED) && (eventFilterPolicyRegistry.ignorePredicate().test(AuditEventMetaInfo.EMPTY) == false)) {
logger.info("{}[ip_filter] [connection_granted]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", localNodeInfo.prefix,
NetworkAddress.format(inetAddress), profile, rule);
}
@ -403,7 +437,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
if (events.contains(CONNECTION_DENIED) && filterPolicyPredicate.test(AuditEventMetaInfo.EMPTY) == false) {
if (events.contains(CONNECTION_DENIED) && (eventFilterPolicyRegistry.ignorePredicate().test(AuditEventMetaInfo.EMPTY) == false)) {
logger.info("{}[ip_filter] [connection_denied]\torigin_address=[{}], transport_profile=[{}], rule=[{}]", localNodeInfo.prefix,
NetworkAddress.format(inetAddress), profile, rule);
}
@ -413,7 +447,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_GRANTED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -439,7 +473,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
final Optional<String[]> indices = indices(message);
if (filterPolicyPredicate
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
@ -463,8 +497,8 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
@Override
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED) && filterPolicyPredicate
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), Optional.empty())) == false) {
if (events.contains(RUN_AS_DENIED) && (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), Optional.empty())) == false)) {
if (includeRequestBody) {
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], roles=[{}], uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), user.principal(), arrayToCommaDelimitedString(roleNames), request.uri(),
@ -552,27 +586,55 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
* the policy.
*/
private static final class EventFilterPolicy {
final String name;
private final String name;
private final Predicate<String> ignorePrincipalsPredicate;
private final Predicate<String> ignoreRealmsPredicate;
private final Predicate<String> ignoreRolesPredicate;
private final Predicate<String> ignoreIndicesPredicate;
EventFilterPolicy(String name, Settings settings) {
this(name, parsePredicate(FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace(name).get(settings)));
}
/**
* An empty filter list for a field will match events with that field missing.
* An event with an undefined field has the field value the empty string ("") or
* a singleton list of the empty string ([""]).
*/
EventFilterPolicy(String name, Settings settings) {
EventFilterPolicy(String name, Predicate<String> ignorePrincipalsPredicate, Predicate<String> ignoreRealmsPredicate,
Predicate<String> ignoreRolesPredicate, Predicate<String> ignoreIndicesPredicate) {
this.name = name;
ignorePrincipalsPredicate = Automatons.predicate(
emptyStringBuildsEmptyAutomaton(FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace(name).get(settings)));
ignoreRealmsPredicate = Automatons.predicate(
emptyStringBuildsEmptyAutomaton(FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace(name).get(settings)));
ignoreRolesPredicate = Automatons.predicate(
emptyStringBuildsEmptyAutomaton(FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace(name).get(settings)));
ignoreIndicesPredicate = Automatons.predicate(
emptyStringBuildsEmptyAutomaton(FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace(name).get(settings)));
this.ignorePrincipalsPredicate = ignorePrincipalsPredicate;
this.ignoreRealmsPredicate = ignoreRealmsPredicate;
this.ignoreRolesPredicate = ignoreRolesPredicate;
this.ignoreIndicesPredicate = ignoreIndicesPredicate;
}
private EventFilterPolicy changePrincipalsFilter(List<String> filtersList) {
return new EventFilterPolicy(name, parsePredicate(filtersList), ignoreRealmsPredicate, ignoreRolesPredicate,
ignoreIndicesPredicate);
}
private EventFilterPolicy changeRealmsFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, parsePredicate(filtersList), ignoreRolesPredicate,
ignoreIndicesPredicate);
}
private EventFilterPolicy changeRolesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, parsePredicate(filtersList),
ignoreIndicesPredicate);
}
private EventFilterPolicy changeIndicesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate,
parsePredicate(filtersList));
}
static Predicate<String> parsePredicate(List<String> l) {
return Automatons.predicate(emptyStringBuildsEmptyAutomaton(l));
}
/**
@ -581,7 +643,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
* `Automatons.predicate("").test("") == false`
* `Automatons.predicate("//").test("") == true`
*/
private List<String> emptyStringBuildsEmptyAutomaton(List<String> l) {
private static List<String> emptyStringBuildsEmptyAutomaton(List<String> l) {
if (l.isEmpty()) {
return Collections.singletonList("//");
}
@ -594,12 +656,14 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
* predicate of the corresponding field.
*/
Predicate<AuditEventMetaInfo> ignorePredicate() {
return (eventInfo) -> {
return ignorePrincipalsPredicate.test(eventInfo.principal)
&& ignoreRealmsPredicate.test(eventInfo.realm)
&& eventInfo.roles.get().allMatch(ignoreRolesPredicate)
&& eventInfo.indices.get().allMatch(ignoreIndicesPredicate);
};
return eventInfo -> ignorePrincipalsPredicate.test(eventInfo.principal) && ignoreRealmsPredicate.test(eventInfo.realm)
&& eventInfo.roles.get().allMatch(ignoreRolesPredicate) && eventInfo.indices.get().allMatch(ignoreIndicesPredicate);
}
@Override
public String toString() {
return "[users]:" + ignorePrincipalsPredicate.toString() + "&[realms]:" + ignoreRealmsPredicate.toString() + "&[roles]:"
+ ignoreRolesPredicate.toString() + "&[indices]:" + ignoreIndicesPredicate.toString();
}
}
@ -607,19 +671,46 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
* Builds the filter predicates for all the policies. Predicates of all policies
* are ORed together, so that an audit event matching any policy is ignored.
*/
private static final class EventFilterPolicyRegistry {
private final Map<String, Predicate<AuditEventMetaInfo>> policyMap;
static final class EventFilterPolicyRegistry {
private volatile Map<String, EventFilterPolicy> policyMap;
private volatile Predicate<AuditEventMetaInfo> predicate;
EventFilterPolicyRegistry(Settings settings) {
final Map<String, Predicate<AuditEventMetaInfo>> map = new HashMap<>();
private EventFilterPolicyRegistry(Settings settings) {
final MapBuilder<String, EventFilterPolicy> mapBuilder = MapBuilder.newMapBuilder();
for (final String policyName : settings.getGroups(FILTER_POLICY_PREFIX, true).keySet()) {
map.put(policyName, new EventFilterPolicy(policyName, settings).ignorePredicate());
mapBuilder.put(policyName, new EventFilterPolicy(policyName, settings));
}
policyMap = Collections.unmodifiableMap(map);
policyMap = mapBuilder.immutableMap();
// precompute predicate
predicate = buildIgnorePredicate(policyMap);
}
private Optional<EventFilterPolicy> get(String policyName) {
return Optional.ofNullable(policyMap.get(policyName));
}
private synchronized void set(String policyName, EventFilterPolicy eventFilterPolicy) {
policyMap = MapBuilder.newMapBuilder(policyMap).put(policyName, eventFilterPolicy).immutableMap();
// precompute predicate
predicate = buildIgnorePredicate(policyMap);
}
Predicate<AuditEventMetaInfo> ignorePredicate() {
return policyMap.values().stream().reduce(x -> false, (x, y) -> x.or(y));
return predicate;
}
private static Predicate<AuditEventMetaInfo> buildIgnorePredicate(Map<String, EventFilterPolicy> policyMap) {
return policyMap.values().stream().map(EventFilterPolicy::ignorePredicate).reduce(x -> false, (x, y) -> x.or(y));
}
@Override
public String toString() {
final Map<String, EventFilterPolicy> treeMap = new TreeMap<>(policyMap);
final StringBuilder sb = new StringBuilder();
for (final Map.Entry<String, EventFilterPolicy> entry : treeMap.entrySet()) {
sb.append(entry.getKey()).append(":").append(entry.getValue().toString());
}
return sb.toString();
}
}
@ -674,7 +765,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
void updateLocalNodeInfo(DiscoveryNode newLocalNode) {
// check if local node changed
final DiscoveryNode localNode = localNodeInfo.localNode;
if (localNode == null || localNode.equals(newLocalNode) == false) {
if ((localNode == null) || (localNode.equals(newLocalNode) == false)) {
// no need to synchronize, called only from the cluster state applier thread
localNodeInfo = new LocalNodeInfo(settings, newLocalNode);
}

View File

@ -0,0 +1,154 @@
/*
* 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.logfile;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.junit.BeforeClass;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ClusterScope(scope = TEST, numDataNodes = 1)
public class AuditTrailFilteringUpdateTests extends SecurityIntegTestCase {
private static Settings startupFilterSettings;
private static Settings updateFilterSettings;
@BeforeClass
public static void startupFilterSettings() {
final Settings.Builder settingsBuilder = Settings.builder();
// generate random filter policies
for (int i = 0; i < randomIntBetween(0, 4); i++) {
settingsBuilder.put(randomFilterPolicySettings("startupPolicy" + i));
}
startupFilterSettings = settingsBuilder.build();
}
@BeforeClass
public static void updateFilterSettings() {
final Settings.Builder settingsBuilder = Settings.builder();
// generate random filter policies
for (int i = 0; i < randomIntBetween(1, 4); i++) {
settingsBuilder.put(randomFilterPolicySettings("updatePolicy" + i));
}
updateFilterSettings = settingsBuilder.build();
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
final Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put(super.nodeSettings(nodeOrdinal));
// enable auditing
settingsBuilder.put("xpack.security.audit.enabled", "true");
settingsBuilder.put("xpack.security.audit.outputs", "logfile");
// add only startup filter policies
settingsBuilder.put(startupFilterSettings);
return settingsBuilder.build();
}
public void testDynamicSettings() throws Exception {
final ClusterService clusterService = mock(ClusterService.class);
final ClusterSettings clusterSettings = mockClusterSettings();
when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
final Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put(startupFilterSettings);
settingsBuilder.put(updateFilterSettings);
// reference audit trail containing all filters
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
final String expected = auditTrail.eventFilterPolicyRegistry.toString();
// update settings on internal cluster
updateSettings(updateFilterSettings);
final String actual = ((LoggingAuditTrail) internalCluster().getInstances(AuditTrailService.class)
.iterator()
.next()
.getAuditTrails()
.iterator()
.next()).eventFilterPolicyRegistry.toString();
assertEquals(expected, actual);
}
public void testInvalidSettings() throws Exception {
final String invalidLuceneRegex = "/invalid";
final Settings.Builder settingsBuilder = Settings.builder();
final String[] allSettingsKeys = new String[] { "xpack.security.audit.logfile.events.ignore_filters.invalid.users",
"xpack.security.audit.logfile.events.ignore_filters.invalid.realms",
"xpack.security.audit.logfile.events.ignore_filters.invalid.roles",
"xpack.security.audit.logfile.events.ignore_filters.invalid.indices" };
settingsBuilder.put(randomFrom(allSettingsKeys), invalidLuceneRegex);
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> client().admin().cluster().prepareUpdateSettings().setTransientSettings(settingsBuilder.build()).get());
assertThat(e.getMessage(), containsString("illegal value can't update"));
}
private void updateSettings(Settings settings) {
if (randomBoolean()) {
assertAcked(client().admin().cluster().prepareUpdateSettings().setPersistentSettings(settings));
} else {
assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(settings));
}
}
private static List<String> randomNonEmptyListOfFilteredNames(String... namePrefix) {
final List<String> filtered = new ArrayList<>(4);
for (int i = 0; i < randomIntBetween(1, 4); i++) {
filtered.add(Strings.arrayToCommaDelimitedString(namePrefix) + randomAlphaOfLengthBetween(1, 4));
}
return filtered;
}
private static Settings randomFilterPolicySettings(String policyName) {
final Settings.Builder settingsBuilder = Settings.builder();
do {
if (randomBoolean()) {
// filter by username
final List<String> filteredUsernames = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters." + policyName + ".users", filteredUsernames);
}
if (randomBoolean()) {
// filter by realms
final List<String> filteredRealms = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters." + policyName + ".realms", filteredRealms);
}
if (randomBoolean()) {
// filter by roles
final List<String> filteredRoles = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters." + policyName + ".roles", filteredRoles);
}
if (randomBoolean()) {
// filter by indices
final List<String> filteredIndices = randomNonEmptyListOfFilteredNames();
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters." + policyName + ".indices", filteredIndices);
}
} while (settingsBuilder.build().isEmpty());
assertFalse(settingsBuilder.build().isEmpty());
return settingsBuilder.build();
}
private ClusterSettings mockClusterSettings() {
final List<Setting<?>> settingsList = new ArrayList<>();
LoggingAuditTrail.registerSettings(settingsList);
settingsList.addAll(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
return new ClusterSettings(Settings.EMPTY, new HashSet<>(settingsList));
}
}

View File

@ -11,6 +11,8 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
@ -38,6 +40,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@ -71,6 +74,8 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
when(localNode.getHostAddress()).thenReturn(buildNewFakeTransportAddress().toString());
clusterService = mock(ClusterService.class);
when(clusterService.localNode()).thenReturn(localNode);
final ClusterSettings clusterSettings = mockClusterSettings();
when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
Mockito.doAnswer((Answer) invocation -> {
final LoggingAuditTrail arg0 = (LoggingAuditTrail) invocation.getArguments()[0];
arg0.updateLocalNodeInfo(localNode);
@ -107,7 +112,8 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
final LoggingAuditTrail auditTrail = new LoggingAuditTrail(settingsBuilder.build(), clusterService, logger, threadContext);
// all fields match
assertTrue("Matches the filter predicate.", auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(
assertTrue("Matches the filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(
Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
@ -120,21 +126,23 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
}
// one field does not match or is empty
assertFalse("Does not match the filter predicate because of the user.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertFalse("Does not match the filter predicate because of the empty user.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.empty(), Optional.of(randomFrom(filteredRealms)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertFalse("Does not match the filter predicate because of the realm.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertFalse("Does not match the filter predicate because of the empty realm.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.empty(),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.empty(),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final List<String> someRolesDoNotMatch = new ArrayList<>(randomSubsetOf(randomIntBetween(0, filteredRoles.size()), filteredRoles));
@ -142,12 +150,12 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
someRolesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
}
assertFalse("Does not match the filter predicate because of some of the roles.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), Optional.of(someRolesDoNotMatch.toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final Optional<String[]> emptyRoles = randomBoolean() ? Optional.empty() : Optional.of(new String[0]);
assertFalse("Does not match the filter predicate because of the empty roles.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), emptyRoles,
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final List<String> someIndicesDoNotMatch = new ArrayList<>(
@ -155,12 +163,14 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
for (int i = 0; i < randomIntBetween(1, 8); i++) {
someIndicesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
}
assertFalse("Does not match the filter predicate because of some of the indices.", auditTrail.filterPolicyPredicate
assertFalse("Does not match the filter predicate because of some of the indices.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])))));
final Optional<String[]> emptyIndices = randomBoolean() ? Optional.empty() : Optional.of(new String[0]);
assertFalse("Does not match the filter predicate because of the empty indices.", auditTrail.filterPolicyPredicate
assertFalse("Does not match the filter predicate because of the empty indices.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
emptyIndices)));
@ -200,7 +210,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
// all fields match
assertTrue("Matches the filter predicate.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
@ -213,21 +223,23 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
}
// one field does not match or is empty
assertFalse("Does not match the filter predicate because of the user.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertTrue("Matches the filter predicate because of the empty user.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.empty(), Optional.of(randomFrom(filteredRealms)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertFalse("Does not match the filter predicate because of the realm.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
assertTrue("Matches the filter predicate because of the empty realm.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.empty(),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.empty(),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final List<String> someRolesDoNotMatch = new ArrayList<>(randomSubsetOf(randomIntBetween(0, filteredRoles.size()), filteredRoles));
@ -235,12 +247,12 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
someRolesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
}
assertFalse("Does not match the filter predicate because of some of the roles.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), Optional.of(someRolesDoNotMatch.toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final Optional<String[]> emptyRoles = randomBoolean() ? Optional.empty() : Optional.of(new String[0]);
assertTrue("Matches the filter predicate because of the empty roles.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), emptyRoles,
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
final List<String> someIndicesDoNotMatch = new ArrayList<>(
@ -248,12 +260,13 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
for (int i = 0; i < randomIntBetween(1, 8); i++) {
someIndicesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
}
assertFalse("Does not match the filter predicate because of some of the indices.", auditTrail.filterPolicyPredicate
assertFalse("Does not match the filter predicate because of some of the indices.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])))));
final Optional<String[]> emptyIndices = randomBoolean() ? Optional.empty() : Optional.of(new String[0]);
assertTrue("Matches the filter predicate because of the empty indices.", auditTrail.filterPolicyPredicate
assertTrue("Matches the filter predicate because of the empty indices.", auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
emptyIndices)));
@ -300,25 +313,26 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
}
// matches both the first and the second policies
assertTrue("Matches both the first and the second filter predicates.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
// matches first policy but not the second
assertTrue("Matches the first filter predicate but not the second.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(randomFrom(filteredRealms)),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0])),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])))));
// matches the second policy but not the first
assertTrue("Matches the second filter predicate but not the first.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(someRolesDoNotMatch.toArray(new String[0])),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])))));
// matches neither the first nor the second policies
assertFalse("Matches neither the first nor the second filter predicates.",
auditTrail.filterPolicyPredicate.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(someRolesDoNotMatch.toArray(new String[0])),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])))));
@ -1493,7 +1507,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
}
private <T> List<T> randomListFromLengthBetween(List<T> l, int min, int max) {
assert min >= 0 && min <= max && max <= l.size();
assert (min >= 0) && (min <= max) && (max <= l.size());
final int len = randomIntBetween(min, max);
final List<T> ans = new ArrayList<>(len);
while (ans.size() < len) {
@ -1502,6 +1516,13 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
return ans;
}
private ClusterSettings mockClusterSettings() {
final List<Setting<?>> settingsList = new ArrayList<>();
LoggingAuditTrail.registerSettings(settingsList);
settingsList.addAll(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
return new ClusterSettings(settings, new HashSet<>(settingsList));
}
private List<String> randomNonEmptyListOfFilteredNames(String... namePrefix) {
final List<String> filtered = new ArrayList<>(4);
for (int i = 0; i < randomIntBetween(1, 4); i++) {

View File

@ -16,6 +16,8 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -40,8 +42,10 @@ import org.mockito.stubbing.Answer;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -135,6 +139,8 @@ public class LoggingAuditTrailTests extends ESTestCase {
arg0.updateLocalNodeInfo(localNode);
return null;
}).when(clusterService).addListener(Mockito.isA(LoggingAuditTrail.class));
final ClusterSettings clusterSettings = mockClusterSettings();
when(clusterService.getClusterSettings()).thenReturn(clusterSettings);
prefix = LoggingAuditTrail.LocalNodeInfo.resolvePrefix(settings, localNode);
threadContext = new ThreadContext(Settings.EMPTY);
}
@ -794,6 +800,13 @@ public class LoggingAuditTrailTests extends ESTestCase {
return Strings.arrayToCommaDelimitedString(((IndicesRequest) message).indices());
}
private ClusterSettings mockClusterSettings() {
final List<Setting<?>> settingsList = new ArrayList<>();
LoggingAuditTrail.registerSettings(settingsList);
settingsList.addAll(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
return new ClusterSettings(settings, new HashSet<>(settingsList));
}
static class MockMessage extends TransportMessage {
MockMessage(ThreadContext threadContext) throws IOException {