Support audit ignore policy by index privileges

Addressing review feedback
This commit is contained in:
BigPandaToo 2021-02-10 20:34:10 +01:00
parent 697131cf94
commit 35573c8bef
5 changed files with 129 additions and 120 deletions

View file

@ -47,16 +47,6 @@ public class ClusterPermission {
return checks.stream().anyMatch(permission -> permission.check(action, request, authentication));
}
/**
* Checks permission to a cluster action.
*
* @param action cluster action
* @return {@code true} if the specified action execution can be granted by given permission else returns {@code false}
*/
public boolean check(final String action) {
return checks.stream().anyMatch(permission -> permission.check(action));
}
/**
* Checks if the specified {@link ClusterPermission}'s actions are implied by this {@link ClusterPermission}
*
@ -156,14 +146,6 @@ public class ClusterPermission {
*/
boolean check(String action, TransportRequest request, Authentication authentication);
/**
* Checks permission to a cluster action regardless of the request and authentication context.
*
* @param action action name
* @return {@code true} if the specified action execution can be granted by given permission else returns {@code false}
*/
boolean check(String action);
/**
* Checks whether specified {@link PermissionCheck} is implied by this {@link PermissionCheck}.<br>
* This is important method to be considered during implementation as it compares {@link PermissionCheck}s.
@ -196,11 +178,6 @@ public class ClusterPermission {
return actionPredicate.test(action) && extendedCheck(action, request, authentication);
}
@Override
public final boolean check(final String action) {
return actionPredicate.test(action);
}
protected abstract boolean extendedCheck(String action, TransportRequest request, Authentication authentication);
@Override

View file

@ -242,20 +242,6 @@ public class ClusterPrivilegeResolver {
.collect(Collectors.toUnmodifiableList());
}
/**
* Returns the names of privileges that grant the specified action.
* @return A collection of names, ordered (to the extent possible) from least privileged (e.g. {@link #MONITOR})
* to most privileged (e.g. {@link #ALL})
* @see #sortByAccessLevel(Collection)
* @see org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission#check(String)
*/
public static Collection<String> findPrivilegesThatGrant(String action) {
return VALUES.entrySet().stream()
.filter(e -> e.getValue().permission().check(action))
.map(Map.Entry::getKey)
.collect(Collectors.toUnmodifiableList());
}
/**
* Sorts the collection of privileges from least-privilege to most-privilege (to the extent possible),
* returning them in a sorted map keyed by name.

View file

@ -57,6 +57,11 @@ public class ManageOwnApiKeyClusterPrivilege implements NamedClusterPrivilege {
@Override
protected boolean extendedCheck(String action, TransportRequest request, Authentication authentication) {
if (request == null || authentication == null) {
throw new IllegalArgumentException(
"manage own cluster permission check only supported in context of request and authentication");
}
if (request instanceof CreateApiKeyRequest) {
return true;
} else if (request instanceof GetApiKeyRequest) {

View file

@ -71,6 +71,9 @@ import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
import org.elasticsearch.xpack.core.security.authz.permission.IndicesPermission;
import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges;
import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
@ -295,7 +298,10 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).
changeIndexPrivilegesFilter(filtersList);
this.eventFilterPolicyRegistry.set(policyName, newPolicy);
}, (policyName, filtersList) -> EventFilterPolicy.parsePredicate(filtersList));
}, (policyName, filtersList) -> {
EventFilterPolicy.parsePredicate(filtersList);
EventFilterPolicy.testtest(filtersList);
});
clusterService.getClusterSettings().addAffixUpdateConsumer(FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES, (policyName, filtersList) -> {
final Optional<EventFilterPolicy> policy = eventFilterPolicyRegistry.get(policyName);
final EventFilterPolicy newPolicy = policy.orElse(new EventFilterPolicy(policyName, settings)).
@ -321,7 +327,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.empty(),
Optional.empty(),
Optional.empty())) == false) {
Optional.empty(), authentication, null)) == false) {
// this is redundant information maintained for bwc purposes
final String authnRealm = authentication.getAuthenticatedBy().getName();
new LogEntryBuilder()
@ -350,7 +356,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.empty(),
indices,
Optional.of(action))) == false) {
Optional.of(action), authentication, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "authentication_success")
@ -372,7 +378,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (events.contains(ANONYMOUS_ACCESS_DENIED)) {
final Optional<String[]> indices = indices(transportRequest);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action))) == false) {
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action), null,
transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "anonymous_access_denied")
@ -410,7 +417,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (events.contains(AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(transportRequest);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), indices, Optional.of(action))) == false) {
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), indices, Optional.of(action),
null, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "authentication_failed")
@ -448,7 +456,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (events.contains(AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(transportRequest);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action))) == false) {
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action),
null, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "authentication_failed")
@ -467,7 +476,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
@Override
public void authenticationFailed(String requestId, AuthenticationToken token, RestRequest request) {
if (events.contains(AUTHENTICATION_FAILED) && eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), Optional.empty(), Optional.empty())) == false) {
.test(new AuditEventMetaInfo(Optional.of(token), Optional.empty(), Optional.empty(), Optional.empty(), null,
null)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, REST_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "authentication_failed")
@ -488,7 +498,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (events.contains(REALM_AUTHENTICATION_FAILED)) {
final Optional<String[]> indices = indices(transportRequest);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), indices, Optional.of(action))) == false) {
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), indices, Optional.of(action),
null, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "realm_authentication_failed")
@ -509,7 +520,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
@Override
public void authenticationFailed(String requestId, String realm, AuthenticationToken token, RestRequest request) {
if (events.contains(REALM_AUTHENTICATION_FAILED) && eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), Optional.empty(), Optional.empty())) == false) {
.test(new AuditEventMetaInfo(Optional.of(token), Optional.of(realm), Optional.empty(), Optional.empty(),
null, null)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, REST_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "realm_authentication_failed")
@ -536,7 +548,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), indices,
Optional.of(action))) == false) {
Optional.of(action), authentication, msg)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "access_granted")
@ -622,7 +634,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), Optional.ofNullable(indices),
Optional.of(action))) == false) {
Optional.of(action), authentication, null)) == false) {
final LogEntryBuilder logEntryBuilder = new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, eventType == ACCESS_DENIED ? "access_denied" : "access_granted")
@ -658,7 +670,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), indices,
Optional.of(action))) == false) {
Optional.of(action), authentication, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "access_denied")
@ -697,7 +709,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (events.contains(TAMPERED_REQUEST)) {
final Optional<String[]> indices = indices(transportRequest);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action))) == false) {
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), indices, Optional.of(action),
null, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "tampered_request")
@ -722,7 +735,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.empty(),
indices, Optional.of(action))) == false) {
indices, Optional.of(action), authentication, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "tampered_request")
@ -781,7 +794,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), indices, Optional.of(action))) == false) {
Optional.of(authorizationInfo), indices, Optional.of(action), authentication, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "run_as_granted")
@ -807,7 +820,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), indices, Optional.of(action))) == false) {
Optional.of(authorizationInfo), indices, Optional.of(action), authentication, transportRequest)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "run_as_denied")
@ -831,7 +844,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
new AuditEventMetaInfo(Optional.of(authentication.getUser()),
// can be null for API keys created before version 7.7
Optional.ofNullable(ApiKeyService.getCreatorRealmName(authentication)),
Optional.of(authorizationInfo), Optional.empty(), Optional.empty())) == false) {
Optional.of(authorizationInfo), Optional.empty(), Optional.empty(), authentication, null)) == false) {
new LogEntryBuilder()
.with(EVENT_TYPE_FIELD_NAME, REST_ORIGIN_FIELD_VALUE)
.with(EVENT_ACTION_FIELD_NAME, "run_as_denied")
@ -1377,6 +1390,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
private final Predicate<String> ignoreIndicesPredicate;
private final Predicate<String> ignoreIndexPrivilegesPredicate;
private final Predicate<String> ignoreClusterPrivilegesPredicate;
private final ClusterPermission clusterPermission;
private final IndicesPermission indexPermission;
private final ConcurrentHashMap<String, Collection<String>> indexActions = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Collection<String>> clusterActions = new ConcurrentHashMap<>();
@ -1388,15 +1403,6 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
parsePredicate(FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_INDEX_PRIVILEGES.getConcreteSettingForNamespace(name).get(settings)),
parsePredicate(FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES.getConcreteSettingForNamespace(name).get(settings)));
if (FILTER_POLICY_IGNORE_INDEX_PRIVILEGES.getConcreteSettingForNamespace(name).exists(settings) &&
FILTER_POLICY_IGNORE_CLUSTER_PRIVILEGES.getConcreteSettingForNamespace(name).exists(settings)) {
final String message = String.format(
Locale.ROOT,
"Both Index and Cluster privilege ignore filters are set for policy [%s]. " +
"Please update your configuration settings and remove one of these filters to avoid ambiguity.", this.name);
throw new IllegalArgumentException(message);
}
}
/**
@ -1415,6 +1421,35 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
this.ignoreIndicesPredicate = ignoreIndicesPredicate;
this.ignoreIndexPrivilegesPredicate = ignoreIndexPrivilegesPredicate;
this.ignoreClusterPrivilegesPredicate = ignoreClusterPrivilegesPredicate;
if (!ignoreIndexPrivilegesPredicate.test("") && !ignoreClusterPrivilegesPredicate.test("")) {
final String message = String.format(
Locale.ROOT,
"Both Index and Cluster privilege ignore filters are set for policy [%s]. " +
"Please update your configuration settings and remove one of these filters to avoid ambiguity.", this.name);
throw new IllegalArgumentException(message);
}
if (!ignoreClusterPrivilegesPredicate.test("")) {
ClusterPermission.Builder builder = ClusterPermission.builder();
String[] clusterPrivileges = ignoreClusterPrivilegesPredicate.toString().split("\\|");
for (String privilege : clusterPrivileges) {
builder = ClusterPrivilegeResolver.resolve(privilege).buildPermission(builder);
}
this.clusterPermission = builder.build();
} else {
this.clusterPermission = ClusterPermission.NONE;
}
if (!ignoreIndexPrivilegesPredicate.test("")) {
List<IndicesPermission.Group> groups = new ArrayList<>();
groups.add(new IndicesPermission.Group(IndexPrivilege.get(Set.of(ignoreIndexPrivilegesPredicate.toString().split("\\|"))),
FieldPermissions.DEFAULT, null, false, "*"));
this.indexPermission = groups.isEmpty() ? IndicesPermission.NONE :
new IndicesPermission(groups.toArray(new IndicesPermission.Group[groups.size()]));
} else {
this.indexPermission = IndicesPermission.NONE;
}
}
private EventFilterPolicy changePrincipalsFilter(List<String> filtersList) {
@ -1438,8 +1473,13 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
}
private EventFilterPolicy changeIndexPrivilegesFilter(List<String> filtersList) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate, ignoreRolesPredicate,
ignoreIndicesPredicate, parsePredicate(filtersList), ignoreClusterPrivilegesPredicate);
try {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate,
ignoreRolesPredicate, ignoreIndicesPredicate, parsePredicate(filtersList), ignoreClusterPrivilegesPredicate);
} catch (IllegalArgumentException e) {
return new EventFilterPolicy(name, ignorePrincipalsPredicate, ignoreRealmsPredicate,
ignoreRolesPredicate, ignoreIndicesPredicate, ignoreIndexPrivilegesPredicate, ignoreClusterPrivilegesPredicate);
}
}
private EventFilterPolicy changeClusterPrivilegesFilter(List<String> filtersList) {
@ -1451,6 +1491,10 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
return Automatons.predicate(emptyStringBuildsEmptyAutomaton(l));
}
static void testtest(List<String> l) {
throw new IllegalStateException("Cannot dynamically update SSL settings for the exporter");
}
/**
* It is a requirement that empty string filters match empty string fields. In
* this case we require automatons from empty string to match the empty string.
@ -1466,22 +1510,12 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
private boolean ignoreIndexPrivilegesPredicateTest(String action) {
if (ignoreIndexPrivilegesPredicate.test(action)) return true;
Collection<String> privileges = indexActions.get(action);
if (privileges == null) {
privileges = IndexPrivilege.findPrivilegesThatGrant(action);
indexActions.put(action, privileges);
}
return privileges != null && privileges.stream().anyMatch((s) -> ignoreIndexPrivilegesPredicate.test(s));
return indexPermission.check(action);
}
private boolean ignoreClusterPrivilegesPredicateTest(String action) {
private boolean ignoreClusterPrivilegesPredicateTest(String action, TransportRequest request, Authentication authentication) {
if (ignoreClusterPrivilegesPredicate.test(action)) return true;
Collection<String> privileges = clusterActions.get(action);
if (privileges == null) {
privileges = ClusterPrivilegeResolver.findPrivilegesThatGrant(action);
clusterActions.put(action, privileges);
}
return privileges != null && privileges.stream().anyMatch((s) -> ignoreClusterPrivilegesPredicate.test(s));
return clusterPermission.check(action, request, authentication);
}
/**
@ -1492,8 +1526,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
Predicate<AuditEventMetaInfo> ignorePredicate() {
return eventInfo -> eventInfo.principal != null && ignorePrincipalsPredicate.test(eventInfo.principal)
&& eventInfo.realm != null && ignoreRealmsPredicate.test(eventInfo.realm)
&& eventInfo.action != null && (ignoreIndexPrivilegesPredicateTest(eventInfo.action) &&
ignoreClusterPrivilegesPredicateTest(eventInfo.action))
&& eventInfo.action != null && ignoreIndexPrivilegesPredicateTest(eventInfo.action)
&& ignoreClusterPrivilegesPredicateTest(eventInfo.action, eventInfo.transportRequest, eventInfo.authentication)
&& eventInfo.roles.get().allMatch(role -> role != null && ignoreRolesPredicate.test(role))
&& eventInfo.indices.get().allMatch(index -> index != null && ignoreIndicesPredicate.test(index));
}
@ -1565,10 +1599,12 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
final String action;
final Supplier<Stream<String>> roles;
final Supplier<Stream<String>> indices;
final Authentication authentication;
final TransportRequest transportRequest;
// empty is used for events can be filtered out only by the lack of a field
static final AuditEventMetaInfo EMPTY = new AuditEventMetaInfo(Optional.empty(), Optional.empty(), Optional.empty(),
Optional.empty());
Optional.empty(), null, null);
/**
* If a field is missing for an event, its value for filtering purposes is the
@ -1579,7 +1615,8 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
* "elastic" username.
*/
AuditEventMetaInfo(Optional<User> user, Optional<String> realm, Optional<AuthorizationInfo> authorizationInfo,
Optional<String[]> indices, Optional<String> action) {
Optional<String[]> indices, Optional<String> action, Authentication authentication,
TransportRequest transportRequest) {
this.principal = user.map(u -> u.principal()).orElse("");
this.realm = realm.orElse("");
this.action = action.orElse("");
@ -1596,15 +1633,19 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener {
}).map(info -> Arrays.stream((String[]) info.asMap().get("user.roles"))).orElse(Stream.of(""));
this.indices = () -> indices.filter(i -> i.length > 0).filter(a -> Arrays.stream(a).anyMatch(Objects::nonNull))
.map(Arrays::stream).orElse(Stream.of(""));
this.authentication = authentication;
this.transportRequest = transportRequest;
}
AuditEventMetaInfo(Optional<AuthenticationToken> authenticationToken, Optional<String> realm, Optional<String[]> indices,
Optional<String> action) {
Optional<String> action, Authentication authentication, TransportRequest transportRequest) {
this.principal = authenticationToken.map(u -> u.principal()).orElse("");
this.realm = realm.orElse("");
this.action = action.orElse("");
this.roles = () -> Stream.of("");
this.indices = () -> indices.filter(r -> r.length != 0).map(i -> Arrays.stream(i)).orElse(Stream.of(""));
this.authentication = authentication;
this.transportRequest = transportRequest;
}
}

View file

@ -145,7 +145,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
// user field matches
assertTrue("Matches the user filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(
new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.empty(), Optional.empty(), Optional.empty(),
Optional.empty())));
Optional.empty(), null, null)));
final User unfilteredUser = mock(User.class);
if (randomBoolean()) {
when(unfilteredUser.authenticatedUser()).thenReturn(new User(randomFrom(filteredUsernames)));
@ -154,51 +154,51 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
assertFalse("Does not match the user filter predicate because of null username.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(unfilteredUser), Optional.empty(), Optional.empty(), Optional.empty(),
Optional.empty())));
Optional.empty(), null, null)));
// realm field matches
assertTrue("Matches the realm filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(
new AuditEventMetaInfo(Optional.empty(), Optional.of(randomFrom(filteredRealms)), Optional.empty(), Optional.empty(),
Optional.empty())));
Optional.empty(), null, null)));
// null realm field does NOT match
assertFalse("Does not match the realm filter predicate because of null realm.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.ofNullable(null), Optional.empty(), Optional.empty(),
Optional.empty())));
Optional.empty(), null, null)));
// role field matches
assertTrue("Matches the role filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(),
Optional.of(authzInfo(
randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0]))),
Optional.empty(), Optional.empty())));
Optional.empty(), Optional.empty(), null, null)));
// privilege field matches
Random random = random();
assertTrue("Matches the privileges filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(
new AuditEventMetaInfo(Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
// null privilege field does NOT match
assertFalse("Does not matches the privileges filter predicate.", auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
Optional.ofNullable(null))));
Optional.ofNullable(null), null, null)));
final List<String> unfilteredRoles = new ArrayList<>();
unfilteredRoles.add(null);
unfilteredRoles.addAll(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles));
// null role among roles field does NOT match
assertFalse("Does not match the role filter predicate because of null role.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(),
Optional.of(authzInfo(unfilteredRoles.toArray(new String[0]))), Optional.empty(), Optional.empty())));
Optional.of(authzInfo(unfilteredRoles.toArray(new String[0]))), Optional.empty(), Optional.empty(), null, null)));
// indices field matches
assertTrue("Matches the index filter predicate.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.empty())));
Optional.empty(), null, null)));
final List<String> unfilteredIndices = new ArrayList<>();
unfilteredIndices.add(null);
unfilteredIndices.addAll(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices));
// null index among indices field does NOT match
assertFalse("Does not match the indices filter predicate because of null index.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(), Optional.empty(),
Optional.empty(), Optional.of(unfilteredIndices.toArray(new String[0])), Optional.empty())));
Optional.empty(), Optional.of(unfilteredIndices.toArray(new String[0])), Optional.empty(), null, null)));
}
public void testSingleCompletePolicyPredicate() throws Exception {
@ -247,7 +247,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final User unfilteredUser;
if (randomBoolean()) {
unfilteredUser = new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
@ -262,35 +262,35 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the empty user.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(),
Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the realm.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the empty realm.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.empty(),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the empty privileges.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.empty())));
Optional.empty(), null, null)));
final List<String> someRolesDoNotMatch = new ArrayList<>(randomSubsetOf(randomIntBetween(0, filteredRoles.size()), filteredRoles));
for (int i = 0; i < randomIntBetween(1, 8); i++) {
someRolesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
@ -299,13 +299,13 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), Optional.of(authzInfo(someRolesDoNotMatch.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final Optional<AuthorizationInfo> emptyRoles = randomBoolean() ? Optional.empty() : Optional.of(authzInfo(new String[0]));
assertFalse("Does not match the filter predicate because of the empty roles.",
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])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final List<String> someIndicesDoNotMatch = new ArrayList<>(
randomSubsetOf(randomIntBetween(0, filteredIndices.size()), filteredIndices));
for (int i = 0; i < randomIntBetween(1, 8); i++) {
@ -317,14 +317,14 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
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.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)), Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
emptyIndices, Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
emptyIndices, Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
}
public void testSingleCompleteWithEmptyFieldPolicyPredicate() throws Exception {
@ -381,7 +381,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final User unfilteredUser;
if (randomBoolean()) {
unfilteredUser = new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
@ -396,35 +396,35 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertTrue("Matches the filter predicate because of the empty user.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.empty(),
Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the realm.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertTrue("Matches the filter predicate because of the empty realm.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.empty(),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
assertFalse("Does not match the filter predicate because of the pivilege.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)))));
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)), null, null)));
final List<String> someRolesDoNotMatch = new ArrayList<>(randomSubsetOf(randomIntBetween(0, filteredRoles.size()), filteredRoles));
for (int i = 0; i < randomIntBetween(1, 8); i++) {
someRolesDoNotMatch.add(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8));
@ -433,13 +433,13 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(randomFrom(filteredRealms)), Optional.of(authzInfo(someRolesDoNotMatch.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final Optional<AuthorizationInfo> emptyRoles = randomBoolean() ? Optional.empty() : Optional.of(authzInfo(new String[0]));
assertTrue("Matches the filter predicate because of the empty roles.",
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])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
final List<String> someIndicesDoNotMatch = new ArrayList<>(
randomSubsetOf(randomIntBetween(0, filteredIndices.size()), filteredIndices));
for (int i = 0; i < randomIntBetween(1, 8); i++) {
@ -451,23 +451,23 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
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(authzInfo(
randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0]))),
Optional.empty(), Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.empty(), Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
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(authzInfo(
randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0]))),
Optional.of(new String[0]), Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(new String[0]), Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
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(authzInfo(
randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles).toArray(new String[0]))),
Optional.of(new String[] { null }),
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))))));
Optional.of(filteredActions.get(random.nextInt(filteredActions.size()))), null, null)));
}
public void testTwoPolicyPredicatesWithMissingFields() throws Exception {
@ -518,28 +518,28 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.empty())));
Optional.empty(), null, null)));
// matches first policy but not the second
assertTrue("Matches the first filter predicate but not the second.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(randomFrom(filteredRealms)),
Optional.of(authzInfo(randomSubsetOf(randomIntBetween(1, filteredRoles.size()), filteredRoles)
.toArray(new String[0]))),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])), Optional.of("_action"))));
Optional.of(someIndicesDoNotMatch.toArray(new String[0])), Optional.of("_action"), null, null)));
// matches the second policy but not the first
assertTrue("Matches the second filter predicate but not the first.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(randomFrom(filteredUsers)),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(authzInfo(someRolesDoNotMatch.toArray(new String[0]))),
Optional.of(randomSubsetOf(randomIntBetween(1, filteredIndices.size()), filteredIndices).toArray(new String[0])),
Optional.empty())));
Optional.empty(), null, null)));
// matches neither the first nor the second policies
assertFalse("Matches neither the first nor the second filter predicates.",
auditTrail.eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(unfilteredUser),
Optional.of(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 8)),
Optional.of(authzInfo(someRolesDoNotMatch.toArray(new String[0]))),
Optional.of(someIndicesDoNotMatch.toArray(new String[0])), Optional.empty())));
Optional.of(someIndicesDoNotMatch.toArray(new String[0])), Optional.empty(), null, null)));
}
public void testUsersFilter() throws Exception {
@ -2033,7 +2033,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
for (int i = 0; i < listOfActions.size(); i++) {
Collection<String> privileges = AuthorizationService.isIndexAction(listOfActions.get(i)) ?
IndexPrivilege.findPrivilegesThatGrant(listOfActions.get(i)) :
ClusterPrivilegeResolver.findPrivilegesThatGrant(listOfActions.get(i));
ClusterPrivilegeResolver.findPrivilegesThatGrant(listOfActions.get(i), null, null);
assertNotNull(privileges);
filtered.addAll(privileges);
}