Realm along the principal in audit authz events (elastic/x-pack-elasticsearch#3260)

Add realm name to all authz audit events: accessDenied, accessGranted,
runAsDenied and runAsGranted.
These event types receive the following attributes: realm,
run_by_realm and run_as_realm to go along with with the existing
attributes: principal, run_by_principal and run_as_principal. The
'effective realm name' (run_as_realm or run_by_realm) is certainly
filterable by ignore policies.

Original commit: elastic/x-pack-elasticsearch@cb3801e197
This commit is contained in:
Albert Zaharovits 2018-03-18 11:27:28 +02:00 committed by GitHub
parent 14acdcb4f7
commit 7ea79c88ab
27 changed files with 811 additions and 604 deletions

View File

@ -69,6 +69,12 @@
"realm": {
"type": "keyword"
},
"run_by_realm": {
"type": "keyword"
},
"run_as_realm": {
"type": "keyword"
},
"transport_profile": {
"type": "keyword"
},

View File

@ -162,15 +162,13 @@ public class SecurityActionFilter extends AbstractComponent implements ActionFil
final AuthorizationUtils.AsyncAuthorizer asyncAuthorizer = new AuthorizationUtils.AsyncAuthorizer(authentication, listener,
(userRoles, runAsRoles) -> {
authzService.authorize(authentication, securityAction, request, userRoles, runAsRoles);
final User user = authentication.getUser();
/*
* We use a separate concept for code that needs to be run after authentication and authorization that could
* affect the running of the action. This is done to make it more clear of the state of the request.
*/
for (RequestInterceptor interceptor : requestInterceptors) {
if (interceptor.supports(request)) {
interceptor.intercept(request, user, runAsRoles != null ? runAsRoles : userRoles, securityAction);
interceptor.intercept(request, authentication, runAsRoles != null ? runAsRoles : userRoles, securityAction);
}
}
listener.onResponse(null);

View File

@ -16,6 +16,7 @@ import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
@ -35,7 +36,8 @@ public class BulkShardRequestInterceptor extends AbstractComponent implements Re
this.licenseState = licenseState;
}
public void intercept(BulkShardRequest request, User user, Role userPermissions, String action) {
@Override
public void intercept(BulkShardRequest request, Authentication authentication, Role userPermissions, String action) {
if (licenseState.isDocumentAndFieldLevelSecurityAllowed() == false) {
return;
}

View File

@ -10,10 +10,10 @@ import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
import org.elasticsearch.xpack.core.security.user.User;
/**
* Base class for interceptors that disables features when field level security is configured for indices a request
@ -32,7 +32,8 @@ abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request extends I
this.licenseState = licenseState;
}
public void intercept(Request request, User user, Role userPermissions, String action) {
@Override
public void intercept(Request request, Authentication authentication, Role userPermissions, String action) {
if (licenseState.isDocumentAndFieldLevelSecurityAllowed() == false) {
return;
}

View File

@ -13,11 +13,11 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
import org.elasticsearch.xpack.core.security.support.Exceptions;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import java.util.HashMap;
@ -37,7 +37,7 @@ public final class IndicesAliasesRequestInterceptor implements RequestIntercepto
}
@Override
public void intercept(IndicesAliasesRequest request, User user, Role userPermissions, String action) {
public void intercept(IndicesAliasesRequest request, Authentication authentication, Role userPermissions, String action) {
if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
for (IndicesAliasesRequest.AliasActions aliasAction : request.getAliasActions()) {
@ -67,7 +67,7 @@ public final class IndicesAliasesRequestInterceptor implements RequestIntercepto
permissionsMap.computeIfAbsent(alias, userPermissions.indices()::allowedActionsMatcher);
if (Operations.subsetOf(aliasPermissions, indexPermissions) == false) {
// TODO we've already audited a access granted event so this is going to look ugly
auditTrailService.accessDenied(user, action, request, userPermissions.names());
auditTrailService.accessDenied(authentication, action, request, userPermissions.names());
throw Exceptions.authorizationError("Adding an alias is not allowed when the alias " +
"has more permissions than any of the indices");
}

View File

@ -6,8 +6,8 @@
package org.elasticsearch.xpack.security.action.interceptor;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
import org.elasticsearch.xpack.core.security.user.User;
/**
* A request interceptor can introspect a request and modify it.
@ -18,7 +18,7 @@ public interface RequestInterceptor<Request> {
* If {@link #supports(TransportRequest)} returns <code>true</code> this interceptor will introspect the request
* and potentially modify it.
*/
void intercept(Request request, User user, Role userPermissions, String action);
void intercept(Request request, Authentication authentication, Role userPermissions, String action);
/**
* Returns whether this request interceptor should intercept the specified request.

View File

@ -16,11 +16,11 @@ import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
import org.elasticsearch.xpack.core.security.support.Exceptions;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
public final class ResizeRequestInterceptor extends AbstractComponent implements RequestInterceptor<ResizeRequest> {
@ -38,7 +38,7 @@ public final class ResizeRequestInterceptor extends AbstractComponent implements
}
@Override
public void intercept(ResizeRequest request, User user, Role userPermissions, String action) {
public void intercept(ResizeRequest request, Authentication authentication, Role userPermissions, String action) {
if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(request.getSourceIndex());
@ -57,7 +57,7 @@ public final class ResizeRequestInterceptor extends AbstractComponent implements
final Automaton targetIndexPermissions = userPermissions.indices().allowedActionsMatcher(request.getTargetIndexRequest().index());
if (Operations.subsetOf(targetIndexPermissions, sourceIndexPermissions) == false) {
// TODO we've already audited a access granted event so this is going to look ugly
auditTrailService.accessDenied(user, action, request, userPermissions.names());
auditTrailService.accessDenied(authentication, action, request, userPermissions.names());
throw Exceptions.authorizationError("Resizing an index is not allowed when the target index " +
"has more permissions than the source index");
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.security.audit;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
@ -37,9 +38,9 @@ public interface AuditTrail {
void authenticationFailed(String realm, AuthenticationToken token, RestRequest request);
void accessGranted(User user, String action, TransportMessage message, String[] roleNames);
void accessGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames);
void accessDenied(User user, String action, TransportMessage message, String[] roleNames);
void accessDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames);
void tamperedRequest(RestRequest request);
@ -51,9 +52,9 @@ public interface AuditTrail {
void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule);
void runAsGranted(User user, String action, TransportMessage message, String[] roleNames);
void runAsGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames);
void runAsDenied(User user, String action, TransportMessage message, String[] roleNames);
void runAsDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames);
void runAsDenied(User user, RestRequest request, String[] roleNames);
void runAsDenied(Authentication authentication, RestRequest request, String[] roleNames);
}

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
@ -130,19 +131,19 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
}
@Override
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void accessGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.accessGranted(user, action, message, roleNames);
auditTrail.accessGranted(authentication, action, message, roleNames);
}
}
}
@Override
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
public void accessDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.accessDenied(user, action, message, roleNames);
auditTrail.accessDenied(authentication, action, message, roleNames);
}
}
}
@ -191,28 +192,28 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsGranted(user, action, message, roleNames);
auditTrail.runAsGranted(authentication, action, message, roleNames);
}
}
}
@Override
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsDenied(user, action, message, roleNames);
auditTrail.runAsDenied(authentication, action, message, roleNames);
}
}
}
@Override
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
public void runAsDenied(Authentication authentication, RestRequest request, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsDenied(user, request, roleNames);
auditTrail.runAsDenied(authentication, request, roleNames);
}
}
}

View File

@ -47,6 +47,7 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.XPackClientPlugin;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.index.IndexAuditTrailField;
import org.elasticsearch.xpack.core.security.user.SystemUser;
@ -437,8 +438,8 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void authenticationSuccess(String realm, User user, RestRequest request) {
if (events.contains(AUTHENTICATION_SUCCESS)) {
try {
enqueue(message("authentication_success", realm, user, null, request), "authentication_success");
} catch (Exception e) {
enqueue(message("authentication_success", new Tuple<>(realm, realm), user, null, request), "authentication_success");
} catch (final Exception e) {
logger.warn("failed to index audit event: [authentication_success]", e);
}
}
@ -448,8 +449,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void authenticationSuccess(String realm, User user, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_SUCCESS)) {
try {
enqueue(message("authentication_success", action, user, null, realm, null, message), "authentication_success");
} catch (Exception e) {
enqueue(message("authentication_success", action, user, null, new Tuple<>(realm, realm), null, message),
"authentication_success");
} catch (final Exception e) {
logger.warn("failed to index audit event: [authentication_success]", e);
}
}
@ -555,25 +557,34 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void accessGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
final User user = authentication.getUser();
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
final boolean logSystemAccessGranted = isSystem && events.contains(SYSTEM_ACCESS_GRANTED);
final boolean shouldLog = logSystemAccessGranted || (isSystem == false && events.contains(ACCESS_GRANTED));
if (shouldLog) {
try {
enqueue(message("access_granted", action, user, roleNames, null, indices(message), message), "access_granted");
} catch (Exception e) {
assert authentication.getAuthenticatedBy() != null;
final String authRealmName = authentication.getAuthenticatedBy().getName();
final String lookRealmName = authentication.getLookedUpBy() == null ? null : authentication.getLookedUpBy().getName();
enqueue(message("access_granted", action, user, roleNames, new Tuple(authRealmName, lookRealmName), indices(message),
message), "access_granted");
} catch (final Exception e) {
logger.warn("failed to index audit event: [access_granted]", e);
}
}
}
@Override
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED) && XPackUser.is(user) == false) {
public void accessDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED) && (XPackUser.is(authentication.getUser()) == false)) {
try {
enqueue(message("access_denied", action, user, roleNames, null, indices(message), message), "access_denied");
} catch (Exception e) {
assert authentication.getAuthenticatedBy() != null;
final String authRealmName = authentication.getAuthenticatedBy().getName();
final String lookRealmName = authentication.getLookedUpBy() == null ? null : authentication.getLookedUpBy().getName();
enqueue(message("access_denied", action, authentication.getUser(), roleNames, new Tuple(authRealmName, lookRealmName),
indices(message), message), "access_denied");
} catch (final Exception e) {
logger.warn("failed to index audit event: [access_denied]", e);
}
}
@ -635,40 +646,53 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_GRANTED)) {
try {
enqueue(message("run_as_granted", action, user, roleNames, null, null, message), "run_as_granted");
} catch (Exception e) {
assert authentication.getAuthenticatedBy() != null;
final String authRealmName = authentication.getAuthenticatedBy().getName();
final String lookRealmName = authentication.getLookedUpBy() == null ? null : authentication.getLookedUpBy().getName();
enqueue(message("run_as_granted", action, authentication.getUser(), roleNames, new Tuple<>(authRealmName, lookRealmName),
null, message), "run_as_granted");
} catch (final Exception e) {
logger.warn("failed to index audit event: [run_as_granted]", e);
}
}
}
@Override
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", action, user, roleNames, null, null, message), "run_as_denied");
} catch (Exception e) {
assert authentication.getAuthenticatedBy() != null;
final String authRealmName = authentication.getAuthenticatedBy().getName();
final String lookRealmName = authentication.getLookedUpBy() == null ? null : authentication.getLookedUpBy().getName();
enqueue(message("run_as_denied", action, authentication.getUser(), roleNames, new Tuple<>(authRealmName, lookRealmName),
null, message), "run_as_denied");
} catch (final Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
}
}
@Override
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
public void runAsDenied(Authentication authentication, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", null, user, roleNames, request), "run_as_denied");
} catch (Exception e) {
assert authentication.getAuthenticatedBy() != null;
final String authRealmName = authentication.getAuthenticatedBy().getName();
final String lookRealmName = authentication.getLookedUpBy() == null ? null : authentication.getLookedUpBy().getName();
enqueue(message("run_as_denied", new Tuple<>(authRealmName, lookRealmName), authentication.getUser(), roleNames, request),
"run_as_denied");
} catch (final Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
}
}
private Message message(String type, @Nullable String action, @Nullable User user, @Nullable String[] roleNames, @Nullable String realm,
@Nullable Set<String> indices, TransportMessage message) throws Exception {
private Message message(String type, @Nullable String action, @Nullable User user, @Nullable String[] roleNames,
@Nullable Tuple<String, String> realms, @Nullable Set<String> indices, TransportMessage message)
throws Exception {
Message msg = new Message().start();
common("transport", type, msg.builder);
@ -677,34 +701,52 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
if (action != null) {
msg.builder.field(Field.ACTION, action);
}
if (user != null) {
if (user.isRunAs()) {
if ("run_as_granted".equals(type) || "run_as_denied".equals(type)) {
msg.builder.field(Field.PRINCIPAL, user.authenticatedUser().principal());
msg.builder.field(Field.RUN_AS_PRINCIPAL, user.principal());
} else {
// TODO: this doesn't make sense...
msg.builder.field(Field.PRINCIPAL, user.principal());
msg.builder.field(Field.RUN_BY_PRINCIPAL, user.authenticatedUser().principal());
}
} else {
msg.builder.field(Field.PRINCIPAL, user.principal());
}
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
addUserAndRealmFields(msg.builder, type, user, realms);
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
if (indices != null) {
msg.builder.array(Field.INDICES, indices.toArray(Strings.EMPTY_ARRAY));
}
if (realm != null) {
msg.builder.field(Field.REALM, realm);
}
msg.builder.field(Field.REQUEST, message.getClass().getSimpleName());
return msg.end();
}
private void addUserAndRealmFields(XContentBuilder builder, String type, @Nullable User user, @Nullable Tuple<String, String> realms)
throws IOException {
if (user != null) {
if (user.isRunAs()) {
if ("run_as_granted".equals(type) || "run_as_denied".equals(type)) {
builder.field(Field.PRINCIPAL, user.authenticatedUser().principal());
builder.field(Field.RUN_AS_PRINCIPAL, user.principal());
if (realms != null) {
// realms.v1() is the authenticating realm
builder.field(Field.REALM, realms.v1());
// realms.v2() is the lookup realm
builder.field(Field.RUN_AS_REALM, realms.v2());
}
} else {
// TODO: this doesn't make sense...
builder.field(Field.PRINCIPAL, user.principal());
builder.field(Field.RUN_BY_PRINCIPAL, user.authenticatedUser().principal());
if (realms != null) {
// realms.v2() is the lookup realm
builder.field(Field.REALM, realms.v2());
// realms.v1() is the authenticating realm
builder.field(Field.RUN_BY_REALM, realms.v1());
}
}
} else {
builder.field(Field.PRINCIPAL, user.principal());
if (realms != null) {
// realms.v1() is the authenticating realm
builder.field(Field.REALM, realms.v1());
}
}
}
}
// FIXME - clean up the message generation
private Message message(String type, @Nullable String action, @Nullable AuthenticationToken token,
@Nullable String realm, @Nullable Set<String> indices, TransportMessage message) throws Exception {
@ -765,25 +807,15 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
return msg.end();
}
private Message message(String type, @Nullable String realm, @Nullable User user, @Nullable String[] roleNames, RestRequest request)
throws Exception {
private Message message(String type, @Nullable Tuple<String,String> realms, @Nullable User user, @Nullable String[] roleNames,
RestRequest request) throws Exception {
Message msg = new Message().start();
common("rest", type, msg.builder);
if (user != null) {
if (user.isRunAs()) {
msg.builder.field(Field.PRINCIPAL, user.principal());
msg.builder.field(Field.RUN_BY_PRINCIPAL, user.authenticatedUser().principal());
} else {
msg.builder.field(Field.PRINCIPAL, user.principal());
}
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
}
if (realm != null) {
msg.builder.field(Field.REALM, realm);
addUserAndRealmFields(msg.builder, type, user, realms);
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
if (includeRequestBody) {
msg.builder.field(Field.REQUEST_BODY, restRequestContent(request));
@ -1139,7 +1171,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
String PRINCIPAL = "principal";
String ROLE_NAMES = "roles";
String RUN_AS_PRINCIPAL = "run_as_principal";
String RUN_AS_REALM = "run_as_realm";
String RUN_BY_PRINCIPAL = "run_by_principal";
String RUN_BY_REALM = "run_by_realm";
String ACTION = "action";
String INDICES = "indices";
String REQUEST = "request";

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.support.Automatons;
import org.elasticsearch.xpack.core.security.user.SystemUser;
@ -334,21 +335,22 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void accessGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
final User user = authentication.getUser();
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || ((isSystem == false) && events.contains(ACCESS_GRANTED))) {
final Optional<String[]> indices = indices(message);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(user),
Optional.of(effectiveRealmName(authentication)), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [access_granted]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), principal(user),
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), subject(authentication),
arrayToCommaDelimitedString(roleNames), action, arrayToCommaDelimitedString(indices.get()),
message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_granted]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user),
originAttributes(threadContext, message, localNodeInfo), subject(authentication),
arrayToCommaDelimitedString(roleNames), action, message.getClass().getSimpleName());
}
}
@ -356,20 +358,20 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
public void accessDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED)) {
final Optional<String[]> indices = indices(message);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
Optional.of(effectiveRealmName(authentication)), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info("{}[transport] [access_denied]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), principal(user),
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), subject(authentication),
arrayToCommaDelimitedString(roleNames), action, arrayToCommaDelimitedString(indices.get()),
message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_denied]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user),
originAttributes(threadContext, message, localNodeInfo), subject(authentication),
arrayToCommaDelimitedString(roleNames), action, message.getClass().getSimpleName());
}
}
@ -444,25 +446,21 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsGranted(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_GRANTED)) {
final Optional<String[]> indices = indices(message);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
Optional.of(effectiveRealmName(authentication)), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info(
"{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}],"
+ " action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo),
user.authenticatedUser().principal(), user.principal(), arrayToCommaDelimitedString(roleNames), action,
arrayToCommaDelimitedString(indices.get()), message.getClass().getSimpleName());
logger.info("{}[transport] [run_as_granted]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), runAsSubject(authentication),
arrayToCommaDelimitedString(roleNames), action, arrayToCommaDelimitedString(indices.get()),
message.getClass().getSimpleName());
} else {
logger.info(
"{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}],"
+ " action=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo),
user.authenticatedUser().principal(), user.principal(), arrayToCommaDelimitedString(roleNames), action,
logger.info("{}[transport] [run_as_granted]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), runAsSubject(authentication),
arrayToCommaDelimitedString(roleNames), action,
message.getClass().getSimpleName());
}
}
@ -470,46 +468,67 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
public void runAsDenied(Authentication authentication, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
final Optional<String[]> indices = indices(message);
if (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), indices)) == false) {
if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
Optional.of(effectiveRealmName(authentication)), Optional.of(roleNames), indices)) == false) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices.isPresent()) {
logger.info(
"{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}],"
+ " action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo),
user.authenticatedUser().principal(), user.principal(), arrayToCommaDelimitedString(roleNames), action,
arrayToCommaDelimitedString(indices.get()), message.getClass().getSimpleName());
} else {
logger.info(
"{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}],"
+ " action=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo),
user.authenticatedUser().principal(), user.principal(), arrayToCommaDelimitedString(roleNames), action,
logger.info("{}[transport] [run_as_denied]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), runAsSubject(authentication),
arrayToCommaDelimitedString(roleNames), action, arrayToCommaDelimitedString(indices.get()),
message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [run_as_denied]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), runAsSubject(authentication),
arrayToCommaDelimitedString(roleNames), action, message.getClass().getSimpleName());
}
}
}
}
@Override
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED) && (eventFilterPolicyRegistry.ignorePredicate()
.test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.of(roleNames), Optional.empty())) == false)) {
public void runAsDenied(Authentication authentication, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)
&& (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()),
Optional.of(effectiveRealmName(authentication)), 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(),
logger.info("{}[rest] [run_as_denied]\t{}, {}, roles=[{}], uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), runAsSubject(authentication), arrayToCommaDelimitedString(roleNames), request.uri(),
restRequestContent(request));
} else {
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], roles=[{}], uri=[{}]", localNodeInfo.prefix,
hostAttributes(request), user.principal(), arrayToCommaDelimitedString(roleNames), request.uri());
logger.info("{}[rest] [run_as_denied]\t{}, {}, roles=[{}], uri=[{}]", localNodeInfo.prefix, hostAttributes(request),
runAsSubject(authentication), arrayToCommaDelimitedString(roleNames), request.uri());
}
}
}
static String runAsSubject(Authentication authentication) {
final StringBuilder sb = new StringBuilder("principal=[");
sb.append(authentication.getUser().authenticatedUser().principal());
sb.append("], realm=[");
sb.append(authentication.getAuthenticatedBy().getName());
sb.append("], run_as_principal=[");
sb.append(authentication.getUser().principal());
if (authentication.getLookedUpBy() != null) {
sb.append("], run_as_realm=[").append(authentication.getLookedUpBy().getName());
}
sb.append("]");
return sb.toString();
}
static String subject(Authentication authentication) {
final StringBuilder sb = new StringBuilder("principal=[");
sb.append(authentication.getUser().principal()).append("], realm=[");
if (authentication.getUser().isRunAs()) {
sb.append(authentication.getLookedUpBy().getName()).append("], run_by_principal=[");
sb.append(authentication.getUser().authenticatedUser().principal()).append("], run_by_realm=[");
}
sb.append(authentication.getAuthenticatedBy().getName()).append("]");
return sb.toString();
}
private static String hostAttributes(RestRequest request) {
String formattedAddress;
final SocketAddress socketAddress = request.getRemoteAddress();
@ -556,6 +575,11 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
return Optional.empty();
}
static String effectiveRealmName(Authentication authentication) {
return authentication.getLookedUpBy() != null ? authentication.getLookedUpBy().getName()
: authentication.getAuthenticatedBy().getName();
}
static String principal(User user) {
final StringBuilder builder = new StringBuilder("principal=[");
builder.append(user.principal());
@ -583,7 +607,7 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
* that will be ignored, aka filtered out, aka not logged. The event can be
* filtered by the following fields : `user`, `realm`, `role` and `index`.
* Predicates on each field are ANDed together to form the filter predicate of
* the policy.
* the policy.
*/
private static final class EventFilterPolicy {
private final String name;

View File

@ -364,7 +364,8 @@ public class AuthenticationService extends AbstractComponent {
} else {
assert runAsUsername.isEmpty() : "the run as username may not be empty";
logger.debug("user [{}] attempted to runAs with an empty username", user.principal());
listener.onFailure(request.runAsDenied(new User(runAsUsername, null, user), authenticationToken));
listener.onFailure(request.runAsDenied(
new Authentication(new User(runAsUsername, null, user), authenticatedBy, lookedupBy), authenticationToken));
}
} else {
finishAuthentication(user);
@ -467,7 +468,7 @@ public class AuthenticationService extends AbstractComponent {
abstract ElasticsearchSecurityException anonymousAccessDenied();
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
abstract ElasticsearchSecurityException runAsDenied(Authentication authentication, AuthenticationToken token);
abstract void authenticationSuccess(String realm, User user);
@ -524,8 +525,8 @@ public class AuthenticationService extends AbstractComponent {
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, action, message, Role.EMPTY.names());
ElasticsearchSecurityException runAsDenied(Authentication authentication, AuthenticationToken token) {
auditTrail.runAsDenied(authentication, action, message, Role.EMPTY.names());
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@ -586,8 +587,8 @@ public class AuthenticationService extends AbstractComponent {
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, request, Role.EMPTY.names());
ElasticsearchSecurityException runAsDenied(Authentication authentication, AuthenticationToken token) {
auditTrail.runAsDenied(authentication, request, Role.EMPTY.names());
return failureHandler.failedAuthentication(request, token, threadContext);
}

View File

@ -151,7 +151,7 @@ public class AuthorizationService extends AbstractComponent {
if (SystemUser.isAuthorized(action)) {
putTransientIfNonExisting(AuthorizationServiceField.INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
putTransientIfNonExisting(ROLE_NAMES_KEY, new String[] { SystemUser.ROLE_NAME });
grant(authentication, action, request, new String[] { SystemUser.ROLE_NAME });
auditTrail.accessGranted(authentication, action, request, new String[] { SystemUser.ROLE_NAME });
return;
}
throw denial(authentication, action, request, new String[] { SystemUser.ROLE_NAME });
@ -168,7 +168,7 @@ public class AuthorizationService extends AbstractComponent {
if (authentication.getLookedUpBy() == null) {
throw denyRunAs(authentication, action, request, permission.names());
} else if (permission.runAs().check(authentication.getUser().principal())) {
grantRunAs(authentication, action, request, permission.names());
auditTrail.runAsGranted(authentication, action, request, permission.names());
permission = runAsRole;
} else {
throw denyRunAs(authentication, action, request, permission.names());
@ -181,7 +181,7 @@ public class AuthorizationService extends AbstractComponent {
ClusterPermission cluster = permission.cluster();
if (cluster.check(action) || checkSameUserPermissions(action, request, authentication)) {
putTransientIfNonExisting(AuthorizationServiceField.INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request, permission.names());
@ -200,7 +200,7 @@ public class AuthorizationService extends AbstractComponent {
}
// we check if the user can execute the action, without looking at indices, which will be authorized at the shard level
if (permission.indices().check(action)) {
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request, permission.names());
@ -211,7 +211,7 @@ public class AuthorizationService extends AbstractComponent {
}
// we check if the user can execute the action, without looking at indices, which will be authorized at the shard level
if (permission.indices().check(action)) {
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request, permission.names());
@ -222,7 +222,7 @@ public class AuthorizationService extends AbstractComponent {
+ action + "] is a proxy action");
}
if (permission.indices().check(action)) {
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
} else {
// we do this here in addition to the denial below since we might run into an assertion on scroll request below if we
@ -251,7 +251,7 @@ public class AuthorizationService extends AbstractComponent {
// we store the request as a transient in the ThreadContext in case of a authorization failure at the shard
// level. If authorization fails we will audit a access_denied message and will use the request to retrieve
// information such as the index and the incoming address of the request
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
}
} else {
@ -287,7 +287,7 @@ public class AuthorizationService extends AbstractComponent {
//'-*' matches no indices so we allow the request to go through, which will yield an empty response
if (resolvedIndices.isNoIndicesPlaceholder()) {
putTransientIfNonExisting(AuthorizationServiceField.INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_NO_INDICES);
grant(authentication, action, request, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
return;
}
@ -333,7 +333,7 @@ public class AuthorizationService extends AbstractComponent {
authorizeBulkItems(authentication, (BulkShardRequest) request, permission, metaData, localIndices, authorizedIndices);
}
grant(authentication, action, originalRequest, permission.names());
auditTrail.accessGranted(authentication, action, request, permission.names());
}
private boolean hasSecurityIndexAccess(IndicesAccessControl indicesAccessControl) {
@ -421,7 +421,7 @@ public class AuthorizationService extends AbstractComponent {
try {
return indicesAndAliasesResolver.resolve(request, metaData, authorizedIndices);
} catch (Exception e) {
auditTrail.accessDenied(authentication.getUser(), action, request, permission.names());
auditTrail.accessDenied(authentication, action, request, permission.names());
throw e;
}
}
@ -548,24 +548,16 @@ public class AuthorizationService extends AbstractComponent {
}
ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.accessDenied(authentication.getUser(), action, request, roleNames);
auditTrail.accessDenied(authentication, action, request, roleNames);
return denialException(authentication, action);
}
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request,
String[] roleNames) {
auditTrail.runAsDenied(authentication.getUser(), action, request, roleNames);
auditTrail.runAsDenied(authentication, action, request, roleNames);
return denialException(authentication, action);
}
private void grant(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.accessGranted(authentication.getUser(), action, request, roleNames);
}
private void grantRunAs(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.runAsGranted(authentication.getUser(), action, request, roleNames);
}
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
final User authUser = authentication.getUser().authenticatedUser();
// Special case for anonymous user

View File

@ -94,7 +94,7 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
final boolean sameUser = samePrincipal && sameRealmType;
if (sameUser == false) {
auditTrailService.accessDenied(current.getUser(), action, request, roleNames);
auditTrailService.accessDenied(current, action, request, roleNames);
throw new SearchContextMissingException(id);
}
}

View File

@ -14,6 +14,8 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
@ -37,7 +39,8 @@ public class IndicesAliasesRequestInterceptorTests extends ESTestCase {
when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(true);
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
AuditTrailService auditTrailService = new AuditTrailService(Settings.EMPTY, Collections.emptyList(), licenseState);
User user = new User("john", "role");
Authentication authentication = new Authentication(new User("john", "role"), new RealmRef(null, null, null),
new RealmRef(null, null, null));
final FieldPermissions fieldPermissions;
final boolean useFls = randomBoolean();
if (useFls) {
@ -70,7 +73,7 @@ public class IndicesAliasesRequestInterceptorTests extends ESTestCase {
indicesAliasesRequest.addAliasAction(IndicesAliasesRequest.AliasActions.removeIndex().index("foofoo"));
}
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> interceptor.intercept(indicesAliasesRequest, user, role, action));
() -> interceptor.intercept(indicesAliasesRequest, authentication, role, action));
assertEquals("Alias requests are not allowed for users who have field or document level security enabled on one of the indices",
securityException.getMessage());
}
@ -81,7 +84,8 @@ public class IndicesAliasesRequestInterceptorTests extends ESTestCase {
when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(true);
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
AuditTrailService auditTrailService = new AuditTrailService(Settings.EMPTY, Collections.emptyList(), licenseState);
User user = new User("john", "role");
Authentication authentication = new Authentication(new User("john", "role"), new RealmRef(null, null, null),
new RealmRef(null, null, null));
Role role = Role.builder()
.add(IndexPrivilege.ALL, "alias")
.add(IndexPrivilege.READ, "index")
@ -102,7 +106,7 @@ public class IndicesAliasesRequestInterceptorTests extends ESTestCase {
}
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> interceptor.intercept(indicesAliasesRequest, user, role, action));
() -> interceptor.intercept(indicesAliasesRequest, authentication, role, action));
assertEquals("Adding an alias is not allowed when the alias has more permissions than any of the indices",
securityException.getMessage());
@ -115,6 +119,6 @@ public class IndicesAliasesRequestInterceptorTests extends ESTestCase {
if (randomBoolean()) {
successRequest.addAliasAction(IndicesAliasesRequest.AliasActions.removeIndex().index("foofoo"));
}
interceptor.intercept(successRequest, user, role, action);
interceptor.intercept(successRequest, authentication, role, action);
}
}

View File

@ -16,6 +16,8 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
@ -41,7 +43,7 @@ public class ResizeRequestInterceptorTests extends ESTestCase {
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext);
AuditTrailService auditTrailService = new AuditTrailService(Settings.EMPTY, Collections.emptyList(), licenseState);
User user = new User("john", "role");
final Authentication authentication = new Authentication(new User("john", "role"), new RealmRef(null, null, null), null);
final FieldPermissions fieldPermissions;
final boolean useFls = randomBoolean();
if (useFls) {
@ -66,7 +68,7 @@ public class ResizeRequestInterceptorTests extends ESTestCase {
new ResizeRequestInterceptor(Settings.EMPTY, threadPool, licenseState, auditTrailService);
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> resizeRequestInterceptor.intercept(new ResizeRequest("bar", "foo"), user, role, action));
() -> resizeRequestInterceptor.intercept(new ResizeRequest("bar", "foo"), authentication, role, action));
assertEquals("Resize requests are not allowed for users when field or document level security is enabled on the source index",
securityException.getMessage());
}
@ -79,7 +81,7 @@ public class ResizeRequestInterceptorTests extends ESTestCase {
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext);
AuditTrailService auditTrailService = new AuditTrailService(Settings.EMPTY, Collections.emptyList(), licenseState);
User user = new User("john", "role");
final Authentication authentication = new Authentication(new User("john", "role"), new RealmRef(null, null, null), null);
Role role = Role.builder()
.add(IndexPrivilege.ALL, "target")
.add(IndexPrivilege.READ, "source")
@ -90,11 +92,11 @@ public class ResizeRequestInterceptorTests extends ESTestCase {
ResizeRequestInterceptor resizeRequestInterceptor =
new ResizeRequestInterceptor(Settings.EMPTY, threadPool, licenseState, auditTrailService);
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> resizeRequestInterceptor.intercept(new ResizeRequest("target", "source"), user, role, action));
() -> resizeRequestInterceptor.intercept(new ResizeRequest("target", "source"), authentication, role, action));
assertEquals("Resizing an index is not allowed when the target index has more permissions than the source index",
securityException.getMessage());
// swap target and source for success
resizeRequestInterceptor.intercept(new ResizeRequest("source", "target"), user, role, action);
resizeRequestInterceptor.intercept(new ResizeRequest("source", "target"), authentication, role, action);
}
}

View File

@ -10,6 +10,8 @@ import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
@ -137,13 +139,14 @@ public class AuditTrailServiceTests extends ESTestCase {
}
public void testAccessGranted() throws Exception {
User user = new User("_username", "r1");
Authentication authentication =new Authentication(new User("_username", "r1"), new RealmRef(null, null, null),
new RealmRef(null, null, null));
String[] roles = new String[] { randomAlphaOfLengthBetween(1, 6) };
service.accessGranted(user, "_action", message, roles);
service.accessGranted(authentication, "_action", message, roles);
verify(licenseState).isAuditingAllowed();
if (isAuditingAllowed) {
for (AuditTrail auditTrail : auditTrails) {
verify(auditTrail).accessGranted(user, "_action", message, roles);
verify(auditTrail).accessGranted(authentication, "_action", message, roles);
}
} else {
verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()]));
@ -151,13 +154,14 @@ public class AuditTrailServiceTests extends ESTestCase {
}
public void testAccessDenied() throws Exception {
User user = new User("_username", "r1");
Authentication authentication = new Authentication(new User("_username", "r1"), new RealmRef(null, null, null),
new RealmRef(null, null, null));
String[] roles = new String[] { randomAlphaOfLengthBetween(1, 6) };
service.accessDenied(user, "_action", message, roles);
service.accessDenied(authentication, "_action", message, roles);
verify(licenseState).isAuditingAllowed();
if (isAuditingAllowed) {
for (AuditTrail auditTrail : auditTrails) {
verify(auditTrail).accessDenied(user, "_action", message, roles);
verify(auditTrail).accessDenied(authentication, "_action", message, roles);
}
} else {
verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()]));

View File

@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicReference;
import static org.elasticsearch.test.SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.iterableWithSize;
@ -90,7 +91,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationServiceField.RUN_AS_USER_HEADER, EXECUTE_USER));
fail("request should have failed");
} catch (ResponseException e) {
} catch (final ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
@ -112,7 +113,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationServiceField.RUN_AS_USER_HEADER, ""));
fail("request should have failed");
} catch (ResponseException e) {
} catch (final ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
@ -121,19 +122,21 @@ public class AuditTrailTests extends SecurityIntegTestCase {
assertThat(events, iterableWithSize(1));
final Map<String, Object> event = events.iterator().next();
assertThat(event.get(IndexAuditTrail.Field.TYPE), equalTo("run_as_denied"));
assertThat(event.get(IndexAuditTrail.Field.PRINCIPAL), equalTo(""));
assertThat(event.get(IndexAuditTrail.Field.RUN_BY_PRINCIPAL), equalTo(AUTHENTICATE_USER));
assertThat(event.get(IndexAuditTrail.Field.PRINCIPAL), equalTo(AUTHENTICATE_USER));
assertThat(event.get(IndexAuditTrail.Field.RUN_AS_PRINCIPAL), equalTo(""));
assertThat(event.get(IndexAuditTrail.Field.REALM), equalTo("file"));
assertThat(event.get(IndexAuditTrail.Field.RUN_AS_REALM), nullValue());
}
private Collection<Map<String, Object>> waitForAuditEvents() throws InterruptedException {
waitForAuditTrailToBeWritten();
AtomicReference<Collection<Map<String, Object>>> eventsRef = new AtomicReference<>();
final AtomicReference<Collection<Map<String, Object>>> eventsRef = new AtomicReference<>();
awaitBusy(() -> {
try {
final Collection<Map<String, Object>> events = getAuditEvents();
eventsRef.set(events);
return events.size() > 0;
} catch (Exception e) {
} catch (final Exception e) {
throw new RuntimeException(e);
}
});
@ -142,14 +145,14 @@ public class AuditTrailTests extends SecurityIntegTestCase {
}
private Collection<Map<String, Object>> getAuditEvents() throws Exception {
final Client client = client();
DateTime now = new DateTime(DateTimeZone.UTC);
String indexName = IndexNameResolver.resolve(IndexAuditTrailField.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY);
final DateTime now = new DateTime(DateTimeZone.UTC);
final String indexName = IndexNameResolver.resolve(IndexAuditTrailField.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY);
assertTrue(awaitBusy(() -> indexExists(client, indexName), 5, TimeUnit.SECONDS));
client.admin().indices().refresh(Requests.refreshRequest(indexName)).get();
SearchRequest request = client.prepareSearch(indexName)
final SearchRequest request = client.prepareSearch(indexName)
.setTypes(IndexAuditTrail.DOC_TYPE)
.setQuery(QueryBuilders.matchAllQuery())
.setSize(1000)
@ -157,7 +160,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
.request();
request.indicesOptions().ignoreUnavailable();
PlainActionFuture<Collection<Map<String, Object>>> listener = new PlainActionFuture();
final PlainActionFuture<Collection<Map<String, Object>>> listener = new PlainActionFuture();
ScrollHelper.fetchAllByEntity(client, request, listener, SearchHit::getSourceAsMap);
return listener.get();

View File

@ -23,6 +23,8 @@ import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.MockTransportClient;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
@ -172,20 +174,19 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
public void testAccessGrantedMuted() {
createAuditTrail(new String[] { "access_granted" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.accessGranted(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
final TransportMessage message = mock(TransportMessage.class);
final Authentication authentication = mock(Authentication.class);
auditTrail.accessGranted(authentication, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(message, user);
verifyZeroInteractions(message);
}
public void testSystemAccessGrantedMuted() {
createAuditTrail(randomFrom(new String[] { "access_granted" }, null));
TransportMessage message = mock(TransportMessage.class);
User user = SystemUser.INSTANCE;
auditTrail.accessGranted(user, "internal:foo", message, new String[] { "role" });
final TransportMessage message = mock(TransportMessage.class);
final Authentication authentication = new Authentication(SystemUser.INSTANCE, new RealmRef(null, null, null), null);
auditTrail.accessGranted(authentication, "internal:foo", message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
@ -194,13 +195,13 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
public void testAccessDeniedMuted() {
createAuditTrail(new String[] { "access_denied" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.accessDenied(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
final TransportMessage message = mock(TransportMessage.class);
final Authentication authentication = mock(Authentication.class);
auditTrail.accessDenied(authentication, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(message, user);
verifyZeroInteractions(message, authentication);
}
public void testTamperedRequestMuted() {
@ -248,25 +249,25 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
public void testRunAsGrantedMuted() {
createAuditTrail(new String[] { "run_as_granted" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
Authentication authentication = mock(Authentication.class);
auditTrail.runAsGranted(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
auditTrail.runAsGranted(authentication, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(message, user);
verifyZeroInteractions(message, authentication);
}
public void testRunAsDeniedMuted() {
createAuditTrail(new String[] { "run_as_denied" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
Authentication authentication = mock(Authentication.class);
auditTrail.runAsDenied(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
auditTrail.runAsDenied(authentication, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
verifyZeroInteractions(message, user);
verifyZeroInteractions(message, authentication);
}
public void testAuthenticationSuccessRest() {

View File

@ -44,6 +44,8 @@ import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.index.IndexAuditTrailField;
import org.elasticsearch.xpack.core.security.user.SystemUser;
@ -563,7 +565,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
user = new User("_username", new String[]{"r1"});
}
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessGranted(user, "_action", message, new String[] { role });
auditor.accessGranted(createAuthentication(user), "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "access_granted");
@ -571,9 +573,12 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("transport", sourceMap.get("origin_type"));
if (runAs) {
assertThat(sourceMap.get("principal"), is("running as"));
assertThat(sourceMap.get("realm"), is("lookRealm"));
assertThat(sourceMap.get("run_by_principal"), is("_username"));
assertThat(sourceMap.get("run_by_realm"), is("authRealm"));
} else {
assertEquals("_username", sourceMap.get("principal"));
assertThat(sourceMap.get("principal"), is("_username"));
assertThat(sourceMap.get("realm"), is("authRealm"));
}
assertEquals("_action", sourceMap.get("action"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
@ -588,13 +593,14 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
initialize(new String[] { "system_access_granted" }, null);
TransportMessage message = randomBoolean() ? new RemoteHostMockMessage() : new LocalHostMockMessage();
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
auditor.accessGranted(createAuthentication(SystemUser.INSTANCE), "internal:_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "access_granted");
Map<String, Object> sourceMap = hit.getSourceAsMap();
assertEquals("transport", sourceMap.get("origin_type"));
assertEquals(SystemUser.INSTANCE.principal(), sourceMap.get("principal"));
assertThat(sourceMap.get("realm"), is("authRealm"));
assertEquals("internal:_action", sourceMap.get("action"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
@ -611,7 +617,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
user = new User("_username", new String[]{"r1"});
}
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessDenied(user, "_action", message, new String[] { role });
auditor.accessDenied(createAuthentication(user), "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
Map<String, Object> sourceMap = hit.getSourceAsMap();
@ -619,9 +625,12 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("transport", sourceMap.get("origin_type"));
if (runAs) {
assertThat(sourceMap.get("principal"), is("running as"));
assertThat(sourceMap.get("realm"), is("lookRealm"));
assertThat(sourceMap.get("run_by_principal"), is("_username"));
assertThat(sourceMap.get("run_by_realm"), is("authRealm"));
} else {
assertEquals("_username", sourceMap.get("principal"));
assertThat(sourceMap.get("principal"), is("_username"));
assertThat(sourceMap.get("realm"), is("authRealm"));
}
assertEquals("_action", sourceMap.get("action"));
if (message instanceof IndicesRequest) {
@ -721,14 +730,16 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
TransportMessage message = randomFrom(new RemoteHostMockMessage(), new LocalHostMockMessage(), new MockIndicesTransportMessage());
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
String role = randomAlphaOfLengthBetween(1, 6);
auditor.runAsGranted(user, "_action", message, new String[] { role });
auditor.runAsGranted(createAuthentication(user), "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "run_as_granted");
Map<String, Object> sourceMap = hit.getSourceAsMap();
assertEquals("transport", sourceMap.get("origin_type"));
assertThat(sourceMap.get("principal"), is("_username"));
assertThat(sourceMap.get("realm"), is("authRealm"));
assertThat(sourceMap.get("run_as_principal"), is("running as"));
assertThat(sourceMap.get("run_as_realm"), is("lookRealm"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
assertEquals("_action", sourceMap.get("action"));
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
@ -738,14 +749,16 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
initialize();
TransportMessage message = randomFrom(new RemoteHostMockMessage(), new LocalHostMockMessage(), new MockIndicesTransportMessage());
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
auditor.runAsDenied(user, "_action", message, new String[] { "r1" });
auditor.runAsDenied(createAuthentication(user), "_action", message, new String[] { "r1" });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "run_as_denied");
Map<String, Object> sourceMap = hit.getSourceAsMap();
assertEquals("transport", sourceMap.get("origin_type"));
assertThat(sourceMap.get("principal"), is("_username"));
assertThat(sourceMap.get("realm"), is("authRealm"));
assertThat(sourceMap.get("run_as_principal"), is("running as"));
assertThat(sourceMap.get("run_as_realm"), is("lookRealm"));
assertEquals("_action", sourceMap.get("action"));
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
}
@ -939,5 +952,10 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
logger.debug("indices {} are yellow", indices.length == 0 ? "[_all]" : indices);
return actionGet.getStatus();
}
private static Authentication createAuthentication(User user) {
final RealmRef lookedUpBy = user.authenticatedUser() == user ? null : new RealmRef("lookRealm", "up", "by");
return new Authentication(user, new RealmRef("authRealm", "test", "foo"), lookedUpBy);
}
}

View File

@ -24,6 +24,8 @@ import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.test.rest.FakeRestRequest.Builder;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.audit.logfile.CapturingLogger;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
@ -362,18 +364,22 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
Collections.emptyList());
}
}
User filteredUser;
final Authentication filteredAuthentication;
if (randomBoolean()) {
filteredUser = new User(randomFrom(allFilteredUsers), new String[] { "r1" }, new User("authUsername", new String[] { "r2" }));
filteredAuthentication = createAuthentication(
new User(randomFrom(allFilteredUsers), new String[] { "r1" }, new User("authUsername", new String[] { "r2" })),
"effectiveRealmName");
} else {
filteredUser = new User(randomFrom(allFilteredUsers), new String[] { "r1" });
filteredAuthentication = createAuthentication(new User(randomFrom(allFilteredUsers), new String[] { "r1" }),
"effectiveRealmName");
}
User unfilteredUser;
final Authentication unfilteredAuthentication;
if (randomBoolean()) {
unfilteredUser = new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4), new String[] { "r1" },
new User("authUsername", new String[] { "r2" }));
unfilteredAuthentication = createAuthentication(new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4),
new String[] { "r1" }, new User("authUsername", new String[] { "r2" })), "effectiveRealmName");
} else {
unfilteredUser = new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4), new String[] { "r1" });
unfilteredAuthentication = createAuthentication(
new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4), new String[] { "r1" }), "effectiveRealmName");
}
final TransportMessage message = randomBoolean() ? new MockMessage(threadContext)
: new MockIndicesRequest(threadContext, new String[] { "idx1", "idx2" });
@ -460,53 +466,55 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// accessGranted
auditTrail.accessGranted(unfilteredUser, "_action", message, new String[] { "role1" });
auditTrail.accessGranted(unfilteredAuthentication, "_action", message, new String[] { "role1" });
assertThat("AccessGranted message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(filteredUser, "_action", message, new String[] { "role1" });
auditTrail.accessGranted(filteredAuthentication, "_action", message, new String[] { "role1" });
assertThat("AccessGranted message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { "role1" });
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessGranted internal message: system user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(unfilteredUser, "internal:_action", message, new String[] { "role1" });
auditTrail.accessGranted(unfilteredAuthentication, "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(filteredUser, "internal:_action", message, new String[] { "role1" });
auditTrail.accessGranted(filteredAuthentication, "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// accessDenied
auditTrail.accessDenied(unfilteredUser, "_action", message, new String[] { "role1" });
auditTrail.accessDenied(unfilteredAuthentication, "_action", message, new String[] { "role1" });
assertThat("AccessDenied message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(filteredUser, "_action", message, new String[] { "role1" });
auditTrail.accessDenied(filteredAuthentication, "_action", message, new String[] { "role1" });
assertThat("AccessDenied message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", message, new String[] { "role1" });
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessDenied internal message: system user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(unfilteredUser, "internal:_action", message, new String[] { "role1" });
auditTrail.accessDenied(unfilteredAuthentication, "internal:_action", message, new String[] { "role1" });
assertThat("AccessDenied internal message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(filteredUser, "internal:_action", message, new String[] { "role1" });
auditTrail.accessDenied(filteredAuthentication, "internal:_action", message, new String[] { "role1" });
assertThat("AccessDenied internal message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
@ -530,12 +538,12 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.tamperedRequest(unfilteredUser, "_action", message);
auditTrail.tamperedRequest(unfilteredAuthentication.getUser(), "_action", message);
assertThat("Tampered message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.tamperedRequest(filteredUser, "_action", message);
auditTrail.tamperedRequest(filteredAuthentication.getUser(), "_action", message);
assertThat("Tampered message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
@ -561,54 +569,54 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// runAsGranted
auditTrail.runAsGranted(unfilteredUser, "_action", new MockMessage(threadContext), new String[] { "role1" });
auditTrail.runAsGranted(unfilteredAuthentication, "_action", new MockMessage(threadContext), new String[] { "role1" });
assertThat("RunAsGranted message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsGranted(filteredUser, "_action", new MockMessage(threadContext), new String[] { "role1" });
auditTrail.runAsGranted(filteredAuthentication, "_action", new MockMessage(threadContext), new String[] { "role1" });
assertThat("RunAsGranted message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// runAsDenied
auditTrail.runAsDenied(unfilteredUser, "_action", new MockMessage(threadContext), new String[] { "role1" });
auditTrail.runAsDenied(unfilteredAuthentication, "_action", new MockMessage(threadContext), new String[] { "role1" });
assertThat("RunAsDenied message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(filteredUser, "_action", new MockMessage(threadContext), new String[] { "role1" });
auditTrail.runAsDenied(filteredAuthentication, "_action", new MockMessage(threadContext), new String[] { "role1" });
assertThat("RunAsDenied message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(unfilteredUser, getRestRequest(), new String[] { "role1" });
auditTrail.runAsDenied(unfilteredAuthentication, getRestRequest(), new String[] { "role1" });
assertThat("RunAsDenied rest request: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(filteredUser, getRestRequest(), new String[] { "role1" });
auditTrail.runAsDenied(filteredAuthentication, getRestRequest(), new String[] { "role1" });
assertThat("RunAsDenied rest request: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// authentication Success
auditTrail.authenticationSuccess("_realm", unfilteredUser, getRestRequest());
auditTrail.authenticationSuccess("_realm", unfilteredAuthentication.getUser(), getRestRequest());
assertThat("AuthenticationSuccess rest request: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", filteredUser, getRestRequest());
auditTrail.authenticationSuccess("_realm", filteredAuthentication.getUser(), getRestRequest());
assertThat("AuthenticationSuccess rest request: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", unfilteredUser, "_action", message);
auditTrail.authenticationSuccess("_realm", unfilteredAuthentication.getUser(), "_action", message);
assertThat("AuthenticationSuccess message: unfiltered user is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", filteredUser, "_action", message);
auditTrail.authenticationSuccess("_realm", filteredAuthentication.getUser(), "_action", message);
assertThat("AuthenticationSuccess message: filtered user is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
@ -728,58 +736,68 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// accessGranted
auditTrail.accessGranted(user, "_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessGranted message: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessGranted message: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessGranted(createAuthentication(user, filteredRealm), "_action", message, new String[] { "role1" });
assertThat("AccessGranted message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessGranted internal message system user: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessGranted internal message system user: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessGranted(createAuthentication(user, unfilteredRealm), "_action", message, new String[] { "role1" });
assertThat("AccessGranted message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "internal:_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessGranted internal message: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessGranted internal message: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, filteredRealm), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessGranted internal message system user: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, unfilteredRealm), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessGranted internal message system user: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(createAuthentication(user, filteredRealm), "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(createAuthentication(user, unfilteredRealm), "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
// accessDenied
auditTrail.accessDenied(user, "_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessDenied message: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessDenied message: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessDenied(createAuthentication(user, filteredRealm), "_action", message, new String[] { "role1" });
assertThat("AccessDenied message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessDenied internal message system user: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessDenied internal message system user: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessDenied(createAuthentication(user, unfilteredRealm), "_action", message, new String[] { "role1" });
assertThat("AccessDenied message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "internal:_action", message, new String[] { "role1" });
if (filterMissingRealm) {
assertThat("AccessGranted internal message: not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("AccessGranted internal message: is filtered out", logOutput.size(), is(1));
}
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, filteredRealm), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessDenied internal message system user: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, unfilteredRealm), "internal:_action", message,
new String[] { "role1" });
assertThat("AccessDenied internal message system user: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(createAuthentication(user, filteredRealm), "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(createAuthentication(user, unfilteredRealm), "internal:_action", message, new String[] { "role1" });
assertThat("AccessGranted internal message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
@ -832,31 +850,38 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// runAsGranted
auditTrail.runAsGranted(user, "_action", new MockMessage(threadContext), new String[] { "role1" });
if (filterMissingRealm) {
assertThat("RunAsGranted message: is not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("RunAsGranted message: is filtered out", logOutput.size(), is(1));
}
auditTrail.runAsGranted(createAuthentication(user, filteredRealm), "_action", new MockMessage(threadContext),
new String[] { "role1" });
assertThat("RunAsGranted message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsGranted(createAuthentication(user, unfilteredRealm), "_action", new MockMessage(threadContext),
new String[] { "role1" });
assertThat("RunAsGranted message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
// runAsDenied
auditTrail.runAsDenied(user, "_action", new MockMessage(threadContext), new String[] { "role1" });
if (filterMissingRealm) {
assertThat("RunAsDenied message: is not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("RunAsDenied message: is filtered out", logOutput.size(), is(1));
}
auditTrail.runAsDenied(createAuthentication(user, filteredRealm), "_action", new MockMessage(threadContext),
new String[] { "role1" });
assertThat("RunAsDenied message: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, getRestRequest(), new String[] { "role1" });
if (filterMissingRealm) {
assertThat("RunAsDenied rest request: is not filtered out by the missing realm filter", logOutput.size(), is(0));
} else {
assertThat("RunAsDenied rest request: is filtered out", logOutput.size(), is(1));
}
auditTrail.runAsDenied(createAuthentication(user, unfilteredRealm), "_action", new MockMessage(threadContext),
new String[] { "role1" });
assertThat("RunAsDenied message: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(createAuthentication(user, filteredRealm), getRestRequest(), new String[] { "role1" });
assertThat("RunAsDenied rest request: filtered realm is not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(createAuthentication(user, unfilteredRealm), getRestRequest(), new String[] { "role1" });
assertThat("RunAsDenied rest request: unfiltered realm is filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
@ -929,11 +954,12 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.otherPolicy.roles", otherRoles);
}
final String[] unfilteredRoles = _unfilteredRoles.toArray(new String[0]);
User user;
final Authentication authentication;
if (randomBoolean()) {
user = new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" }));
authentication = createAuthentication(new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" })),
"effectiveRealmName");
} else {
user = new User("user1", new String[] { "r1" });
authentication = createAuthentication(new User("user1", new String[] { "r1" }), "effectiveRealmName");
}
final TransportMessage message = randomBoolean() ? new MockMessage(threadContext)
: new MockIndicesRequest(threadContext, new String[] { "idx1", "idx2" });
@ -1015,63 +1041,67 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// accessGranted
auditTrail.accessGranted(user, "_action", message, unfilteredRoles);
auditTrail.accessGranted(authentication, "_action", message, unfilteredRoles);
assertThat("AccessGranted message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "_action", message, filteredRoles);
auditTrail.accessGranted(authentication, "_action", message, filteredRoles);
assertThat("AccessGranted message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, unfilteredRoles);
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
unfilteredRoles);
assertThat("AccessGranted internal message system user: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, filteredRoles);
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
filteredRoles);
assertThat("AccessGranted internal message system user: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "internal:_action", message, unfilteredRoles);
auditTrail.accessGranted(authentication, "internal:_action", message, unfilteredRoles);
assertThat("AccessGranted internal message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "internal:_action", message, filteredRoles);
auditTrail.accessGranted(authentication, "internal:_action", message, filteredRoles);
assertThat("AccessGranted internal message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// accessDenied
auditTrail.accessDenied(user, "_action", message, unfilteredRoles);
auditTrail.accessDenied(authentication, "_action", message, unfilteredRoles);
assertThat("AccessDenied message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "_action", message, filteredRoles);
auditTrail.accessDenied(authentication, "_action", message, filteredRoles);
assertThat("AccessDenied message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", message, unfilteredRoles);
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
unfilteredRoles);
assertThat("AccessDenied internal message system user: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", message, filteredRoles);
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", message,
filteredRoles);
assertThat("AccessDenied internal message system user: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "internal:_action", message, unfilteredRoles);
auditTrail.accessDenied(authentication, "internal:_action", message, unfilteredRoles);
assertThat("AccessDenied internal message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "internal:_action", message, filteredRoles);
auditTrail.accessDenied(authentication, "internal:_action", message, filteredRoles);
assertThat("AccessDenied internal message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
@ -1097,39 +1127,39 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// runAsGranted
auditTrail.runAsGranted(user, "_action", new MockMessage(threadContext), unfilteredRoles);
auditTrail.runAsGranted(authentication, "_action", new MockMessage(threadContext), unfilteredRoles);
assertThat("RunAsGranted message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsGranted(user, "_action", new MockMessage(threadContext), filteredRoles);
auditTrail.runAsGranted(authentication, "_action", new MockMessage(threadContext), filteredRoles);
assertThat("RunAsGranted message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// runAsDenied
auditTrail.runAsDenied(user, "_action", new MockMessage(threadContext), unfilteredRoles);
auditTrail.runAsDenied(authentication, "_action", new MockMessage(threadContext), unfilteredRoles);
assertThat("RunAsDenied message: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, "_action", new MockMessage(threadContext), filteredRoles);
auditTrail.runAsDenied(authentication, "_action", new MockMessage(threadContext), filteredRoles);
assertThat("RunAsDenied message: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, getRestRequest(), unfilteredRoles);
auditTrail.runAsDenied(authentication, getRestRequest(), unfilteredRoles);
assertThat("RunAsDenied rest request: unfiltered roles filtered out", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, getRestRequest(), filteredRoles);
auditTrail.runAsDenied(authentication, getRestRequest(), filteredRoles);
assertThat("RunAsDenied rest request: filtered roles not filtered out", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// authentication Success
auditTrail.authenticationSuccess("_realm", user, getRestRequest());
auditTrail.authenticationSuccess("_realm", authentication.getUser(), getRestRequest());
if (filterMissingRoles) {
assertThat("AuthenticationSuccess rest request: is not filtered out by the missing roles filter", logOutput.size(), is(0));
} else {
@ -1138,7 +1168,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", user, "_action", message);
auditTrail.authenticationSuccess("_realm", authentication.getUser(), "_action", message);
if (filterMissingRoles) {
assertThat("AuthenticationSuccess message: is not filtered out by the missing roles filter", logOutput.size(), is(0));
} else {
@ -1195,11 +1225,12 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.otherPolicy.indices", otherIndices);
}
final String[] unfilteredIndices = _unfilteredIndices.toArray(new String[0]);
User user;
final Authentication authentication;
if (randomBoolean()) {
user = new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" }));
authentication = createAuthentication(new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" })),
"effectiveRealmName");
} else {
user = new User("user1", new String[] { "r1" });
authentication = createAuthentication(new User("user1", new String[] { "r1" }), "effectiveRealmName");
}
final MockToken authToken = new MockToken("token1");
final TransportMessage noIndexMessage = new MockMessage(threadContext);
@ -1324,7 +1355,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// accessGranted
auditTrail.accessGranted(user, "_action", noIndexMessage, new String[] { "role1" });
auditTrail.accessGranted(authentication, "_action", noIndexMessage, new String[] { "role1" });
if (filterMissingIndices) {
assertThat("AccessGranted message no index: not filtered out by the missing indices filter", logOutput.size(), is(0));
} else {
@ -1333,17 +1364,20 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "_action", new MockIndicesRequest(threadContext, unfilteredIndices), new String[] { "role1" });
auditTrail.accessGranted(authentication, "_action", new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("AccessGranted message unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(user, "_action", new MockIndicesRequest(threadContext, filteredIndices), new String[] { "role1" });
auditTrail.accessGranted(authentication, "_action", new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("AccessGranted message filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", noIndexMessage, new String[] { "role1" });
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", noIndexMessage,
new String[] { "role1" });
if (filterMissingIndices) {
assertThat("AccessGranted message system user no index: not filtered out by the missing indices filter", logOutput.size(),
is(0));
@ -1353,20 +1387,22 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", new MockIndicesRequest(threadContext, unfilteredIndices),
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action",
new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("AccessGranted message system user unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", new MockIndicesRequest(threadContext, filteredIndices),
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action",
new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("AccessGranted message system user filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// accessDenied
auditTrail.accessDenied(user, "_action", noIndexMessage, new String[] { "role1" });
auditTrail.accessDenied(authentication, "_action", noIndexMessage, new String[] { "role1" });
if (filterMissingIndices) {
assertThat("AccessDenied message no index: not filtered out by the missing indices filter", logOutput.size(), is(0));
} else {
@ -1375,17 +1411,20 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "_action", new MockIndicesRequest(threadContext, unfilteredIndices), new String[] { "role1" });
auditTrail.accessDenied(authentication, "_action", new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("AccessDenied message unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(user, "_action", new MockIndicesRequest(threadContext, filteredIndices), new String[] { "role1" });
auditTrail.accessDenied(authentication, "_action", new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("AccessDenied message filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", noIndexMessage, new String[] { "role1" });
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action", noIndexMessage,
new String[] { "role1" });
if (filterMissingIndices) {
assertThat("AccessDenied message system user no index: not filtered out by the missing indices filter", logOutput.size(),
is(0));
@ -1395,13 +1434,15 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", new MockIndicesRequest(threadContext, unfilteredIndices),
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action",
new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("AccessDenied message system user unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.accessDenied(SystemUser.INSTANCE, "internal:_action", new MockIndicesRequest(threadContext, filteredIndices),
auditTrail.accessDenied(createAuthentication(SystemUser.INSTANCE, "effectiveRealmName"), "internal:_action",
new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("AccessGranted message system user filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
@ -1428,7 +1469,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// runAsGranted
auditTrail.runAsGranted(user, "_action", noIndexMessage, new String[] { "role1" });
auditTrail.runAsGranted(authentication, "_action", noIndexMessage, new String[] { "role1" });
if (filterMissingIndices) {
assertThat("RunAsGranted message no index: not filtered out by missing indices filter", logOutput.size(), is(0));
} else {
@ -1437,18 +1478,20 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsGranted(user, "_action", new MockIndicesRequest(threadContext, unfilteredIndices), new String[] { "role1" });
auditTrail.runAsGranted(authentication, "_action", new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("RunAsGranted message unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsGranted(user, "_action", new MockIndicesRequest(threadContext, filteredIndices), new String[] { "role1" });
auditTrail.runAsGranted(authentication, "_action", new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("RunAsGranted message filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
// runAsDenied
auditTrail.runAsDenied(user, "_action", noIndexMessage, new String[] { "role1" });
auditTrail.runAsDenied(authentication, "_action", noIndexMessage, new String[] { "role1" });
if (filterMissingIndices) {
assertThat("RunAsDenied message no index: not filtered out by missing indices filter", logOutput.size(), is(0));
} else {
@ -1457,17 +1500,19 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, "_action", new MockIndicesRequest(threadContext, unfilteredIndices), new String[] { "role1" });
auditTrail.runAsDenied(authentication, "_action", new MockIndicesRequest(threadContext, unfilteredIndices),
new String[] { "role1" });
assertThat("RunAsDenied message unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, "_action", new MockIndicesRequest(threadContext, filteredIndices), new String[] { "role1" });
auditTrail.runAsDenied(authentication, "_action", new MockIndicesRequest(threadContext, filteredIndices),
new String[] { "role1" });
assertThat("RunAsDenied message filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
auditTrail.runAsDenied(user, getRestRequest(), new String[] { "role1" });
auditTrail.runAsDenied(authentication, getRestRequest(), new String[] { "role1" });
if (filterMissingIndices) {
assertThat("RunAsDenied rest request: not filtered out by missing indices filter", logOutput.size(), is(0));
} else {
@ -1477,7 +1522,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
threadContext.stashContext();
// authentication Success
auditTrail.authenticationSuccess("_realm", user, getRestRequest());
auditTrail.authenticationSuccess("_realm", authentication.getUser(), getRestRequest());
if (filterMissingIndices) {
assertThat("AuthenticationSuccess rest request: is not filtered out by the missing indices filter", logOutput.size(), is(0));
} else {
@ -1486,7 +1531,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", user, "_action", noIndexMessage);
auditTrail.authenticationSuccess("_realm", authentication.getUser(), "_action", noIndexMessage);
if (filterMissingIndices) {
assertThat("AuthenticationSuccess message no index: not filtered out by missing indices filter", logOutput.size(), is(0));
} else {
@ -1495,12 +1540,14 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", user, "_action", new MockIndicesRequest(threadContext, unfilteredIndices));
auditTrail.authenticationSuccess("_realm", authentication.getUser(), "_action",
new MockIndicesRequest(threadContext, unfilteredIndices));
assertThat("AuthenticationSuccess message unfiltered indices: filtered out by indices filter", logOutput.size(), is(1));
logOutput.clear();
threadContext.stashContext();
auditTrail.authenticationSuccess("_realm", user, "_action", new MockIndicesRequest(threadContext, filteredIndices));
auditTrail.authenticationSuccess("_realm", authentication.getUser(), "_action",
new MockIndicesRequest(threadContext, filteredIndices));
assertThat("AuthenticationSuccess message filtered indices: not filtered out by indices filter", logOutput.size(), is(0));
logOutput.clear();
threadContext.stashContext();
@ -1516,6 +1563,15 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
return ans;
}
private static Authentication createAuthentication(User user, String effectiveRealmName) {
if (user.isRunAs()) {
return new Authentication(user,
new RealmRef(UNFILTER_MARKER + randomAlphaOfLength(4), "test", "foo"), new RealmRef(effectiveRealmName, "up", "by"));
} else {
return new Authentication(user, new RealmRef(effectiveRealmName, "test", "foo"), null);
}
}
private ClusterSettings mockClusterSettings() {
final List<Setting<?>> settingsList = new ArrayList<>();
LoggingAuditTrail.registerSettings(settingsList);
@ -1593,4 +1649,4 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
}
}
}

View File

@ -30,6 +30,8 @@ import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.test.rest.FakeRestRequest.Builder;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.core.security.audit.logfile.CapturingLogger;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
@ -346,9 +348,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
user = new User("_username", new String[]{"r1"});
}
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(user, "_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
auditTrail.accessGranted(createAuthentication(user), "_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], realm=[lookRealm], run_by_principal=[_username], run_by_realm=[authRealm]"
: "principal=[_username], realm=[authRealm]") + ", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -361,7 +363,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "_action", message, new String[] { role });
auditTrail.accessGranted(createAuthentication(user), "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -370,22 +372,23 @@ public class LoggingAuditTrailTests extends ESTestCase {
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
final TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE), "internal:_action", message, new String[] { role });
assertEmptyLog(logger);
// test enabled
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "system_access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
final String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
auditTrail.accessGranted(createAuthentication(SystemUser.INSTANCE), "internal:_action", message, new String[] { role });
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal()
+ "], roles=[" + role + "], action=[internal:_action], indices=[" + indices(message)
+ "], realm=[authRealm], roles=[" + role + "], action=[internal:_action], indices=[" + indices(message)
+ "], request=[MockIndicesRequest]");
} else {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal() + "], roles=[" + role + "], action=[internal:_action], request=[MockMessage]");
SystemUser.INSTANCE.principal() + "], realm=[authRealm], roles=[" + role
+ "], action=[internal:_action], request=[MockMessage]");
}
}
@ -402,9 +405,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
user = new User("_username", new String[]{"r1"});
}
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(user, "internal:_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
auditTrail.accessGranted(createAuthentication(user), "internal:_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], realm=[lookRealm], run_by_principal=[_username], run_by_realm=[authRealm]"
: "principal=[_username], realm=[authRealm]") + ", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -417,7 +420,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "internal:_action", message, new String[] { role });
auditTrail.accessGranted(createAuthentication(user), "internal:_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -434,9 +437,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
user = new User("_username", new String[]{"r1"});
}
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessDenied(user, "_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
auditTrail.accessDenied(createAuthentication(user), "_action", message, new String[] { role });
final String userInfo = (runAs ? "principal=[running as], realm=[lookRealm], run_by_principal=[_username], run_by_realm=[authRealm]"
: "principal=[_username], realm=[authRealm]") + ", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -449,7 +452,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessDenied(user, "_action", message, new String[] { role });
auditTrail.accessDenied(createAuthentication(user), "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -569,14 +572,16 @@ public class LoggingAuditTrailTests extends ESTestCase {
final String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
final User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.runAsGranted(user, "_action", message, new String[] { role });
auditTrail.runAsGranted(createAuthentication(user), "_action", message, new String[] { role });
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO,
prefix + "[transport] [run_as_granted]\t" + origins + ", principal=[_username], run_as_principal=[running as], roles=["
prefix + "[transport] [run_as_granted]\t" + origins
+ ", principal=[_username], realm=[authRealm], run_as_principal=[running as], run_as_realm=[lookRealm], roles=["
+ role + "], action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else {
assertMsg(logger, Level.INFO,
prefix + "[transport] [run_as_granted]\t" + origins + ", principal=[_username], run_as_principal=[running as], roles=["
prefix + "[transport] [run_as_granted]\t" + origins
+ ", principal=[_username], realm=[authRealm], run_as_principal=[running as], run_as_realm=[lookRealm], roles=["
+ role + "], action=[_action], request=[MockMessage]");
}
@ -584,7 +589,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsGranted(user, "_action", message, new String[] { role });
auditTrail.runAsGranted(createAuthentication(user), "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -595,14 +600,16 @@ public class LoggingAuditTrailTests extends ESTestCase {
final String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
final User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
final String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.runAsDenied(user, "_action", message, new String[] { role });
auditTrail.runAsDenied(createAuthentication(user), "_action", message, new String[] { role });
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO,
prefix + "[transport] [run_as_denied]\t" + origins + ", principal=[_username], run_as_principal=[running as], roles=["
prefix + "[transport] [run_as_denied]\t" + origins
+ ", principal=[_username], realm=[authRealm], run_as_principal=[running as], run_as_realm=[lookRealm], roles=["
+ role + "], action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
} else {
assertMsg(logger, Level.INFO,
prefix + "[transport] [run_as_denied]\t" + origins + ", principal=[_username], run_as_principal=[running as], roles=["
prefix + "[transport] [run_as_denied]\t" + origins
+ ", principal=[_username], realm=[authRealm], run_as_principal=[running as], run_as_realm=[lookRealm], roles=["
+ role + "], action=[_action], request=[MockMessage]");
}
@ -610,7 +617,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsDenied(user, "_action", message, new String[] { role });
auditTrail.runAsDenied(createAuthentication(user), "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -740,10 +747,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
auditTrail.authenticationFailed(realm, new MockToken(), "_action", message);
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.accessGranted(user, "_action", message, new String[] { role });
auditTrail.accessGranted(createAuthentication(user), "_action", message, new String[] { role });
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.accessDenied(user, "_action", message, new String[] { role });
auditTrail.accessDenied(createAuthentication(user), "_action", message, new String[] { role });
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.tamperedRequest("_action", message);
@ -752,10 +759,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
auditTrail.tamperedRequest(user, "_action", message);
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.runAsGranted(user, "_action", message, new String[] { role });
auditTrail.runAsGranted(createAuthentication(user), "_action", message, new String[] { role });
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.runAsDenied(user, "_action", message, new String[] { role });
auditTrail.runAsDenied(createAuthentication(user), "_action", message, new String[] { role });
assertThat(output.size(), is(logEntriesCount++));
assertThat(output.get(logEntriesCount - 2), not(containsString("indices=[")));
auditTrail.authenticationSuccess(realm, user, "_action", message);
@ -800,6 +807,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
return Strings.arrayToCommaDelimitedString(((IndicesRequest) message).indices());
}
private static Authentication createAuthentication(User user) {
final RealmRef lookedUpBy = user.authenticatedUser() == user ? null : new RealmRef("lookRealm", "up", "by");
return new Authentication(user, new RealmRef("authRealm", "test", "foo"), lookedUpBy);
}
private ClusterSettings mockClusterSettings() {
final List<Setting<?>> settingsList = new ArrayList<>();
LoggingAuditTrail.registerSettings(settingsList);

View File

@ -782,7 +782,7 @@ public class AuthenticationServiceTests extends ESTestCase {
authenticateBlocking(restRequest);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).runAsDenied(any(User.class), eq(restRequest), eq(Role.EMPTY.names()));
verify(auditTrail).runAsDenied(any(Authentication.class), eq(restRequest), eq(Role.EMPTY.names()));
verifyNoMoreInteractions(auditTrail);
}
}
@ -799,7 +799,7 @@ public class AuthenticationServiceTests extends ESTestCase {
authenticateBlocking("_action", message, null);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).runAsDenied(any(User.class), eq("_action"), eq(message), eq(Role.EMPTY.names()));
verify(auditTrail).runAsDenied(any(Authentication.class), eq("_action"), eq(message), eq(Role.EMPTY.names()));
verifyNoMoreInteractions(auditTrail);
}
}

View File

@ -222,62 +222,67 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest request = mock(TransportRequest.class);
// A failure would throw an exception
authorize(createAuthentication(SystemUser.INSTANCE), "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "indices:monitor/whatever", request,
Authentication authentication = createAuthentication(SystemUser.INSTANCE);
authorize(authentication, "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(authentication, "indices:monitor/whatever", request,
new String[] { SystemUser.ROLE_NAME });
authorize(createAuthentication(SystemUser.INSTANCE), "internal:whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "internal:whatever", request, new String[] { SystemUser.ROLE_NAME });
authentication = createAuthentication(SystemUser.INSTANCE);
authorize(authentication, "internal:whatever", request);
verify(auditTrail).accessGranted(authentication, "internal:whatever", request, new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
public void testIndicesActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
final TransportRequest request = mock(TransportRequest.class);
final Authentication authentication = createAuthentication(SystemUser.INSTANCE);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "indices:", request),
() -> authorize(authentication, "indices:", request),
"indices:", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "indices:", request, new String[] { SystemUser.ROLE_NAME });
verify(auditTrail).accessDenied(authentication, "indices:", request, new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
public void testClusterAdminActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
final TransportRequest request = mock(TransportRequest.class);
final Authentication authentication = createAuthentication(SystemUser.INSTANCE);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/whatever", request),
() -> authorize(authentication, "cluster:admin/whatever", request),
"cluster:admin/whatever", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/whatever", request,
verify(auditTrail).accessDenied(authentication, "cluster:admin/whatever", request,
new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
public void testClusterAdminSnapshotStatusActionIsNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
final TransportRequest request = mock(TransportRequest.class);
final Authentication authentication = createAuthentication(SystemUser.INSTANCE);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/snapshot/status", request),
() -> authorize(authentication, "cluster:admin/snapshot/status", request),
"cluster:admin/snapshot/status", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/snapshot/status", request,
verify(auditTrail).accessDenied(authentication, "cluster:admin/snapshot/status", request,
new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
public void testNoRolesCausesDenial() {
TransportRequest request = new SearchRequest();
User user = new User("test user");
final TransportRequest request = new SearchRequest();
final Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, "indices:a", request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
public void testUserWithNoRolesCanPerformRemoteSearch() {
SearchRequest request = new SearchRequest();
request.indices("other_cluster:index1", "*_cluster:index2", "other_cluster:other_*");
User user = new User("test user");
final Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
authorize(createAuthentication(user), SearchAction.NAME, request);
verify(auditTrail).accessGranted(user, SearchAction.NAME, request, Role.EMPTY.names());
authorize(authentication, SearchAction.NAME, request);
verify(auditTrail).accessGranted(authentication, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -289,12 +294,12 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testUserWithNoRolesCannotPerformLocalSearch() {
SearchRequest request = new SearchRequest();
request.indices("no_such_cluster:index");
User user = new User("test user");
final Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, request),
() -> authorize(authentication, SearchAction.NAME, request),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -305,23 +310,23 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testUserWithNoRolesCanPerformMultiClusterSearch() {
SearchRequest request = new SearchRequest();
request.indices("local_index", "wildcard_*", "other_cluster:remote_index", "*:foo?");
User user = new User("test user");
final Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, request),
() -> authorize(authentication, SearchAction.NAME, request),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
public void testUserWithNoRolesCannotSql() {
TransportRequest request = new SqlQueryRequest();
User user = new User("test user");
Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SqlQueryAction.NAME, request),
() -> authorize(authentication, SqlQueryAction.NAME, request),
SqlQueryAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SqlQueryAction.NAME, request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, SqlQueryAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -332,12 +337,12 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testRemoteIndicesOnlyWorkWithApplicableRequestTypes() {
DeleteIndexRequest request = new DeleteIndexRequest();
request.indices("other_cluster:index1", "other_cluster:index2");
User user = new User("test user");
final Authentication authentication = createAuthentication(new User("test user"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), DeleteIndexAction.NAME, request),
() -> authorize(authentication, DeleteIndexAction.NAME, request),
DeleteIndexAction.NAME, "test user");
verify(auditTrail).accessDenied(user, DeleteIndexAction.NAME, request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, DeleteIndexAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -348,26 +353,26 @@ public class AuthorizationServiceTests extends ESTestCase {
new Tuple<>(SqlQueryAction.NAME, new SqlQueryRequest())));
String action = tuple.v1();
TransportRequest request = tuple.v2();
User user = new User("test user", "non-existent-role");
final Authentication authentication = createAuthentication(new User("test user", "non-existent-role"));
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request),
() -> authorize(authentication, action, request),
action, "test user");
verify(auditTrail).accessDenied(user, action, request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, action, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
public void testThatNonIndicesAndNonClusterActionIsDenied() {
TransportRequest request = mock(TransportRequest.class);
User user = new User("test user", "a_all");
RoleDescriptor role = new RoleDescriptor("a_role", null,
final TransportRequest request = mock(TransportRequest.class);
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
final RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "whatever", request),
() -> authorize(authentication, "whatever", request),
"whatever", "test user");
verify(auditTrail).accessDenied(user, "whatever", request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, "whatever", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -379,30 +384,30 @@ public class AuthorizationServiceTests extends ESTestCase {
new Tuple<>(SqlQueryAction.NAME, new SqlQueryRequest()));
String action = tuple.v1();
TransportRequest request = tuple.v2();
User user = new User("test user", "no_indices");
final Authentication authentication = createAuthentication(new User("test user", "no_indices"));
RoleDescriptor role = new RoleDescriptor("a_role", null, null, null);
roleMap.put("no_indices", role);
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request),
() -> authorize(authentication, action, request),
action, "test user");
verify(auditTrail).accessDenied(user, action, request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testElasticUserAuthorizedForNonChangePasswordRequestsWhenNotInSetupMode() {
final User user = new ElasticUser(true);
Tuple<String, TransportRequest> request = randomCompositeRequest();
authorize(createAuthentication(user), request.v1(), request.v2());
final Authentication authentication = createAuthentication(new ElasticUser(true));
final Tuple<String, TransportRequest> request = randomCompositeRequest();
authorize(authentication, request.v1(), request.v2());
verify(auditTrail).accessGranted(user, request.v1(), request.v2(), new String[] { ElasticUser.ROLE_NAME });
verify(auditTrail).accessGranted(authentication, request.v1(), request.v2(), new String[] { ElasticUser.ROLE_NAME });
}
public void testSearchAgainstEmptyCluster() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
mockEmptyMetaData();
@ -413,21 +418,20 @@ public class AuthorizationServiceTests extends ESTestCase {
true, false));
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, searchRequest),
() -> authorize(authentication, SearchAction.NAME, searchRequest),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, searchRequest, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, SearchAction.NAME, searchRequest, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
{
//ignore_unavailable and allow_no_indices both set to true, user is not authorized for this index nor does it exist
SearchRequest searchRequest = new SearchRequest("does_not_exist")
.indicesOptions(IndicesOptions.fromOptions(true, true,
true, false));
authorize(createAuthentication(user), SearchAction.NAME, searchRequest);
verify(auditTrail).accessGranted(user, SearchAction.NAME, searchRequest, new String[] { role.getName() });
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
IndicesAccessControl.IndexAccessControl indexAccessControl =
.indicesOptions(IndicesOptions.fromOptions(true, true, true, false));
authorize(authentication, SearchAction.NAME, searchRequest);
verify(auditTrail).accessGranted(authentication, SearchAction.NAME, searchRequest, new String[] { role.getName() });
final IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
final IndicesAccessControl.IndexAccessControl indexAccessControl =
indicesAccessControl.getIndexPermissions(IndicesAndAliasesResolverField.NO_INDEX_PLACEHOLDER);
assertFalse(indexAccessControl.getFieldPermissions().hasFieldLevelSecurity());
assertNull(indexAccessControl.getQueries());
@ -437,38 +441,38 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testScrollRelatedRequestsAllowed() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
mockEmptyMetaData();
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
authorize(createAuthentication(user), ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(user, ClearScrollAction.NAME, clearScrollRequest, new String[] { role.getName() });
final ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
authorize(authentication, ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(authentication, ClearScrollAction.NAME, clearScrollRequest, new String[] { role.getName() });
SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
authorize(createAuthentication(user), SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(user, SearchScrollAction.NAME, searchScrollRequest, new String[] { role.getName() });
final SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
authorize(authentication, SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(authentication, SearchScrollAction.NAME, searchScrollRequest, new String[] { role.getName() });
// We have to use a mock request for other Scroll actions as the actual requests are package private to SearchTransportService
TransportRequest request = mock(TransportRequest.class);
authorize(createAuthentication(user), SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request,
final TransportRequest request = mock(TransportRequest.class);
authorize(authentication, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(authentication, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request,
authorize(authentication, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(authentication, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request,
authorize(authentication, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(authentication, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request,
authorize(authentication, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(authentication, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request,
authorize(authentication, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(authentication, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -478,13 +482,13 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -496,13 +500,13 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), CreateIndexAction.NAME, request),
() -> authorize(authentication, CreateIndexAction.NAME, request),
IndicesAliasesAction.NAME, "test user");
verify(auditTrail).accessDenied(user, IndicesAliasesAction.NAME, request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, IndicesAliasesAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
@ -514,12 +518,12 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a", "a2").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
authorize(createAuthentication(user), CreateIndexAction.NAME, request);
authorize(authentication, CreateIndexAction.NAME, request);
verify(auditTrail).accessGranted(user, CreateIndexAction.NAME, request, new String[] { role.getName()});
verify(auditTrail).accessGranted(authentication, CreateIndexAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
@ -537,11 +541,11 @@ public class AuthorizationServiceTests extends ESTestCase {
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
final Authentication authentication = createAuthentication(anonymousUser);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(anonymousUser), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", anonymousUser.principal());
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -554,7 +558,7 @@ public class AuthorizationServiceTests extends ESTestCase {
.put(AnonymousUser.ROLES_SETTING.getKey(), "a_all")
.put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false)
.build();
final AnonymousUser anonymousUser = new AnonymousUser(settings);
final Authentication authentication = createAuthentication(new AnonymousUser(settings));
authorizationService = new AuthorizationService(settings, rolesStore, clusterService, auditTrail,
new DefaultAuthenticationFailureHandler(), threadPool, new AnonymousUser(settings));
@ -562,10 +566,10 @@ public class AuthorizationServiceTests extends ESTestCase {
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> authorize(createAuthentication(anonymousUser), "indices:a", request));
final ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> authorize(authentication, "indices:a", request));
assertAuthenticationException(securityException, containsString("action [indices:a] requires authentication"));
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -577,28 +581,29 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
final IndexNotFoundException nfe = expectThrows(
IndexNotFoundException.class,
() -> authorize(createAuthentication(user), GetIndexAction.NAME, request));
() -> authorize(authentication, GetIndexAction.NAME, request));
assertThat(nfe.getIndex(), is(notNullValue()));
assertThat(nfe.getIndex().getName(), is("not-an-index-*"));
verify(auditTrail).accessDenied(user, GetIndexAction.NAME, request, new String[]{ role.getName() });
verify(auditTrail).accessDenied(authentication, GetIndexAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
}
public void testRunAsRequestWithNoRolesUser() {
TransportRequest request = mock(TransportRequest.class);
User user = new User("run as me", null, new User("test user", "admin"));
assertNotEquals(user.authenticatedUser(), user);
final TransportRequest request = mock(TransportRequest.class);
final Authentication authentication = createAuthentication(new User("run as me", null, new User("test user", "admin")));
final User user = new User("run as me", null, new User("test user", "admin"));
assertNotEquals(authentication.getUser().authenticatedUser(), authentication);
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", "test user", "run as me"); // run as [run as me]
verify(auditTrail).runAsDenied(user, "indices:a", request, Role.EMPTY.names());
verify(auditTrail).runAsDenied(authentication, "indices:a", request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -611,7 +616,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(authentication, AuthenticateAction.NAME, request),
AuthenticateAction.NAME, "test user", "run as me"); // run as [run as me]
verify(auditTrail).runAsDenied(user, AuthenticateAction.NAME, request,
verify(auditTrail).runAsDenied(authentication, AuthenticateAction.NAME, request,
new String[] { ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -620,15 +625,16 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest request = mock(TransportRequest.class);
User user = new User("run as me", new String[] { "doesn't exist" }, new User("test user", "can run as"));
assertNotEquals(user.authenticatedUser(), user);
RoleDescriptor role = new RoleDescriptor("can run as", null,
final Authentication authentication = createAuthentication(user);
final RoleDescriptor role = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "not the right user" });
roleMap.put("can run as", role);
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", "test user", "run as me");
verify(auditTrail).runAsDenied(user, "indices:a", request, new String[] { role.getName() });
verify(auditTrail).runAsDenied(authentication, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -637,7 +643,8 @@ public class AuthorizationServiceTests extends ESTestCase {
User authenticatedUser = new User("test user", "can run as");
User user = new User("run as me", new String[] { "b" }, authenticatedUser);
assertNotEquals(user.authenticatedUser(), user);
RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
final Authentication authentication = createAuthentication(user);
final RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "run as me" });
roleMap.put("can run as", runAsRole);
@ -659,13 +666,13 @@ public class AuthorizationServiceTests extends ESTestCase {
}
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
() -> authorize(authentication, "indices:a", request),
"indices:a", "test user", "run as me");
verify(auditTrail).runAsGranted(user, "indices:a", request, new String[] { runAsRole.getName() });
verify(auditTrail).runAsGranted(authentication, "indices:a", request, new String[] { runAsRole.getName() });
if (indexExists) {
verify(auditTrail).accessDenied(user, "indices:a", request, new String[] { bRole.getName() });
verify(auditTrail).accessDenied(authentication, "indices:a", request, new String[] { bRole.getName() });
} else {
verify(auditTrail).accessDenied(user, "indices:a", request, Role.EMPTY.names());
verify(auditTrail).accessDenied(authentication, "indices:a", request, Role.EMPTY.names());
}
verifyNoMoreInteractions(auditTrail);
}
@ -675,7 +682,8 @@ public class AuthorizationServiceTests extends ESTestCase {
User authenticatedUser = new User("test user", new String[] { "can run as" });
User user = new User("run as me", new String[] { "b" }, authenticatedUser);
assertNotEquals(user.authenticatedUser(), user);
RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
final Authentication authentication = createAuthentication(user);
final RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "run as me" });
roleMap.put("can run as", runAsRole);
@ -690,16 +698,16 @@ public class AuthorizationServiceTests extends ESTestCase {
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("all").build() }, null);
roleMap.put("b", bRole);
authorize(createAuthentication(user), "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request, new String[] { runAsRole.getName() });
verify(auditTrail).accessGranted(user, "indices:a", request, new String[] { bRole.getName() });
authorize(authentication, "indices:a", request);
verify(auditTrail).runAsGranted(authentication, "indices:a", request, new String[] { runAsRole.getName() });
verify(auditTrail).accessGranted(authentication, "indices:a", request, new String[] { bRole.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testNonXPackUserCannotExecuteOperationAgainstSecurityIndex() {
RoleDescriptor role = new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null);
User user = new User("all_access_user", "all_access");
final Authentication authentication = createAuthentication(new User("all_access_user", "all_access"));
roleMap.put("all_access", role);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
@ -731,25 +739,25 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request),
() -> authorize(authentication, action, request),
action, "all_access_user");
verify(auditTrail).accessDenied(user, action, request, new String[] { role.getName() });
verify(auditTrail).accessDenied(authentication, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
// we should allow waiting for the health of the index or any index if the user has this permission
ClusterHealthRequest request = new ClusterHealthRequest(SECURITY_INDEX_NAME);
authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request, new String[] { role.getName() });
authorize(authentication, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(authentication, ClusterHealthAction.NAME, request, new String[] { role.getName() });
// multiple indices
request = new ClusterHealthRequest(SECURITY_INDEX_NAME, "foo", "bar");
authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request, new String[] { role.getName() });
authorize(authentication, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(authentication, ClusterHealthAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
SearchRequest searchRequest = new SearchRequest("_all");
authorize(createAuthentication(user), SearchAction.NAME, searchRequest);
final SearchRequest searchRequest = new SearchRequest("_all");
authorize(authentication, SearchAction.NAME, searchRequest);
assertEquals(2, searchRequest.indices().length);
assertEquals(IndicesAndAliasesResolver.NO_INDICES_LIST, Arrays.asList(searchRequest.indices()));
}
@ -757,7 +765,7 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testGrantedNonXPackUserCanExecuteMonitoringOperationsAgainstSecurityIndex() {
RoleDescriptor role = new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null);
User user = new User("all_access_user", "all_access");
final Authentication authentication = createAuthentication(new User("all_access_user", "all_access"));
roleMap.put("all_access", role);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
@ -777,11 +785,11 @@ public class AuthorizationServiceTests extends ESTestCase {
requests.add(new Tuple<>(UpgradeStatusAction.NAME,
new UpgradeStatusRequest().indices(SECURITY_INDEX_NAME)));
for (Tuple<String, ? extends TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() });
for (final Tuple<String, ? extends TransportRequest> requestTuple : requests) {
final String action = requestTuple.v1();
final TransportRequest request = requestTuple.v2();
authorize(authentication, action, request);
verify(auditTrail).accessGranted(authentication, action, request, new String[] { role.getName() });
}
}
@ -819,16 +827,18 @@ public class AuthorizationServiceTests extends ESTestCase {
requests.add(new Tuple<>(ClusterHealthAction.NAME,
new ClusterHealthRequest(SECURITY_INDEX_NAME, "foo", "bar")));
for (Tuple<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
authorize(createAuthentication(superuser), action, request);
verify(auditTrail).accessGranted(superuser, action, request, superuser.roles());
for (final Tuple<String, TransportRequest> requestTuple : requests) {
final String action = requestTuple.v1();
final TransportRequest request = requestTuple.v2();
final Authentication authentication = createAuthentication(superuser);
authorize(authentication, action, request);
verify(auditTrail).accessGranted(authentication, action, request, superuser.roles());
}
}
public void testSuperusersCanExecuteOperationAgainstSecurityIndexWithWildcard() {
final User superuser = new User("custom_admin", ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName());
final Authentication authentication = createAuthentication(superuser);
roleMap.put(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName(), ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
@ -841,7 +851,7 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = SearchAction.NAME;
SearchRequest request = new SearchRequest("_all");
authorize(createAuthentication(superuser), action, request);
verify(auditTrail).accessGranted(superuser, action, request, superuser.roles());
verify(auditTrail).accessGranted(authentication, action, request, superuser.roles());
assertThat(request.indices(), arrayContaining(".security"));
}
@ -888,30 +898,30 @@ public class AuthorizationServiceTests extends ESTestCase {
public void testCompositeActionsAreImmediatelyRejected() {
//if the user has no permission for composite actions against any index, the request fails straight-away in the main action
Tuple<String, TransportRequest> compositeRequest = randomCompositeRequest();
String action = compositeRequest.v1();
TransportRequest request = compositeRequest.v2();
User user = new User("test user", "no_indices");
RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
final Tuple<String, TransportRequest> compositeRequest = randomCompositeRequest();
final String action = compositeRequest.v1();
final TransportRequest request = compositeRequest.v2();
final Authentication authentication = createAuthentication(new User("test user", "no_indices"));
final RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
roleMap.put("no_indices", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request), action, "test user");
verify(auditTrail).accessDenied(user, action, request, new String[] { role.getName() });
() -> authorize(authentication, action, request), action, "test user");
verify(auditTrail).accessDenied(authentication, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testCompositeActionsIndicesAreNotChecked() {
//if the user has permission for some index, the request goes through without looking at the indices, they will be checked later
Tuple<String, TransportRequest> compositeRequest = randomCompositeRequest();
String action = compositeRequest.v1();
TransportRequest request = compositeRequest.v2();
User user = new User("test user", "role");
RoleDescriptor role = new RoleDescriptor("role", null,
final Tuple<String, TransportRequest> compositeRequest = randomCompositeRequest();
final String action = compositeRequest.v1();
final TransportRequest request = compositeRequest.v2();
final Authentication authentication = createAuthentication(new User("test user", "role"));
final RoleDescriptor role = new RoleDescriptor("role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices(randomBoolean() ? "a" : "index").privileges("all").build() },
null);
roleMap.put("role", role);
authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() });
authorize(authentication, action, request);
verify(auditTrail).accessGranted(authentication, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -983,7 +993,7 @@ public class AuthorizationServiceTests extends ESTestCase {
final ShardId shardId = new ShardId("concrete-index", UUID.randomUUID().toString(), 1);
final TransportRequest request = new BulkShardRequest(shardId, WriteRequest.RefreshPolicy.IMMEDIATE, items);
User user = new User("user", "my-role");
final Authentication authentication = createAuthentication(new User("user", "my-role"));
RoleDescriptor role = new RoleDescriptor("my-role", null, new IndicesPrivileges[] {
IndicesPrivileges.builder().indices("concrete-index").privileges("all").build(),
IndicesPrivileges.builder().indices("alias-1").privileges("index").build(),
@ -992,11 +1002,11 @@ public class AuthorizationServiceTests extends ESTestCase {
roleMap.put("my-role", role);
mockEmptyMetaData();
authorize(createAuthentication(user), action, request);
authorize(authentication, action, request);
verify(auditTrail).accessDenied(user, DeleteAction.NAME, request, new String[] { role.getName() }); // alias-1 delete
verify(auditTrail).accessDenied(user, IndexAction.NAME, request, new String[] { role.getName() }); // alias-2 index
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() }); // bulk request is allowed
verify(auditTrail).accessDenied(authentication, DeleteAction.NAME, request, new String[] { role.getName() }); // alias-1 delete
verify(auditTrail).accessDenied(authentication, IndexAction.NAME, request, new String[] { role.getName() }); // alias-2 index
verify(auditTrail).accessGranted(authentication, action, request, new String[] { role.getName() }); // bulk request is allowed
verifyNoMoreInteractions(auditTrail);
}
@ -1013,19 +1023,19 @@ public class AuthorizationServiceTests extends ESTestCase {
final ShardId shardId = new ShardId("concrete-index", UUID.randomUUID().toString(), 1);
final TransportRequest request = new BulkShardRequest(shardId, WriteRequest.RefreshPolicy.IMMEDIATE, items);
User user = new User("user", "my-role");
RoleDescriptor role = new RoleDescriptor("my-role", null,
final Authentication authentication = createAuthentication(new User("user", "my-role"));
final RoleDescriptor role = new RoleDescriptor("my-role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("datemath-*").privileges("index").build() }, null);
roleMap.put("my-role", role);
mockEmptyMetaData();
authorize(createAuthentication(user), action, request);
authorize(authentication, action, request);
verify(auditTrail, Mockito.times(2)).accessDenied(user, DeleteAction.NAME, request,
new String[] { role.getName() }); // both
// deletes
// should fail
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() }); // bulk request is allowed
// both deletes should fail
verify(auditTrail, Mockito.times(2)).accessDenied(authentication, DeleteAction.NAME, request,
new String[] { role.getName() });
// bulk request is allowed
verify(auditTrail).accessGranted(authentication, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -1253,52 +1263,52 @@ public class AuthorizationServiceTests extends ESTestCase {
}
public void testProxyRequestAuthenticationDenied() {
TransportRequest proxiedRequest = new SearchRequest();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, proxiedRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.QUERY_ACTION_NAME);
User user = new User("test user", "no_indices");
RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
final TransportRequest proxiedRequest = new SearchRequest();
final DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
final TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, proxiedRequest);
final String action = TransportActionProxy.getProxyAction(SearchTransportService.QUERY_ACTION_NAME);
final Authentication authentication = createAuthentication(new User("test user", "no_indices"));
final RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
roleMap.put("no_indices", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(user, action, proxiedRequest, new String[] { role.getName() });
() -> authorize(authentication, action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(authentication, action, proxiedRequest, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testProxyRequestAuthenticationGrantedWithAllPrivileges() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
mockEmptyMetaData();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(createAuthentication(user), action, transportRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest, new String[] { role.getName() });
final ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
final TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
final String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(authentication, action, transportRequest);
verify(auditTrail).accessGranted(authentication, action, clearScrollRequest, new String[] { role.getName() });
}
public void testProxyRequestAuthenticationGranted() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read_cross_cluster").build() }, null);
User user = new User("test user", "a_all");
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
roleMap.put("a_all", role);
mockEmptyMetaData();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(createAuthentication(user), action, transportRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest, new String[] { role.getName() });
final ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
final TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
final String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(authentication, action, transportRequest);
verify(auditTrail).accessGranted(authentication, action, clearScrollRequest, new String[] { role.getName() });
}
public void testProxyRequestAuthenticationDeniedWithReadPrivileges() {
User user = new User("test user", "a_all");
RoleDescriptor role = new RoleDescriptor("a_role", null,
final Authentication authentication = createAuthentication(new User("test user", "a_all"));
final RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read").build() }, null);
roleMap.put("a_all", role);
mockEmptyMetaData();
@ -1307,7 +1317,7 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(user, action, clearScrollRequest, new String[] { role.getName() });
() -> authorize(authentication, action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(authentication, action, clearScrollRequest, new String[] { role.getName() });
}
}

View File

@ -118,7 +118,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
expectThrows(SearchContextMissingException.class, () -> listener.validateSearchContext(testSearchContext, request));
assertEquals(testSearchContext.id(), expected.id());
verify(licenseState, times(3)).isAuthAllowed();
verify(auditTrailService).accessDenied(authentication.getUser(), "action", request, authentication.getUser().roles());
verify(auditTrailService).accessDenied(authentication, "action", request, authentication.getUser().roles());
}
// another user running as the original user
@ -152,7 +152,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
expectThrows(SearchContextMissingException.class, () -> listener.validateSearchContext(testSearchContext, request));
assertEquals(testSearchContext.id(), expected.id());
verify(licenseState, times(5)).isAuthAllowed();
verify(auditTrailService).accessDenied(authentication.getUser(), "action", request, authentication.getUser().roles());
verify(auditTrailService).accessDenied(authentication, "action", request, authentication.getUser().roles());
}
}
@ -189,7 +189,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
() -> ensureAuthenticatedUserIsSame(original, differentRealmType, auditTrail, id, action, request,
original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(differentRealmType.getUser(), action, request, original.getUser().roles());
verify(auditTrail).accessDenied(differentRealmType, action, request, original.getUser().roles());
// wrong user
Authentication differentUser =
@ -197,7 +197,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(original, differentUser, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(differentUser.getUser(), action, request, original.getUser().roles());
verify(auditTrail).accessDenied(differentUser, action, request, original.getUser().roles());
// run as different user
Authentication diffRunAs = new Authentication(new User(new User("test2", "role"), new User("authenticated", "runas")),
@ -205,7 +205,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(original, diffRunAs, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(diffRunAs.getUser(), action, request, original.getUser().roles());
verify(auditTrail).accessDenied(diffRunAs, action, request, original.getUser().roles());
// run as different looked up by type
Authentication runAsDiffType = new Authentication(user, new RealmRef("realm", "file", "node"),
@ -213,7 +213,7 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(runAs, runAsDiffType, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(runAsDiffType.getUser(), action, request, original.getUser().roles());
verify(auditTrail).accessDenied(runAsDiffType, action, request, original.getUser().roles());
}
static class TestScrollSearchContext extends TestSearchContext {

View File

@ -17,6 +17,9 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.NotEqualMessageBuilder;
import org.elasticsearch.xpack.qa.sql.security.SqlSecurityTestCase.AuditLogAsserter;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import java.io.IOException;
import java.io.InputStream;
@ -24,10 +27,8 @@ import java.sql.JDBCType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
@ -36,7 +37,6 @@ import static org.elasticsearch.xpack.qa.sql.rest.RestSqlTestCase.randomMode;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static java.util.Collections.emptyMap;
public class RestSqlSecurityIT extends SqlSecurityTestCase {
private static class RestActions implements Actions {
@ -205,6 +205,11 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
super(new RestActions());
}
@Override
protected AuditLogAsserter createAuditLogAsserter() {
return new RestAuditLogAsserter();
}
/**
* Test the hijacking a scroll fails. This test is only implemented for
* REST because it is the only API where it is simple to hijack a scroll.
@ -226,15 +231,37 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
assertThat(e.getMessage(), containsString("No search context found for id"));
assertEquals(404, e.getResponse().getStatusLine().getStatusCode());
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expect(true, SQL_ACTION_NAME, "full_access", empty())
// One scroll access denied per shard
.expect(false, SQL_ACTION_NAME, "full_access", empty(), "InternalScrollSearchRequest")
.expect(false, SQL_ACTION_NAME, "full_access", empty(), "InternalScrollSearchRequest")
.expect(false, SQL_ACTION_NAME, "full_access", empty(), "InternalScrollSearchRequest")
.expect(false, SQL_ACTION_NAME, "full_access", empty(), "InternalScrollSearchRequest")
.expect(false, SQL_ACTION_NAME, "full_access", empty(), "InternalScrollSearchRequest")
.expect("access_denied", SQL_ACTION_NAME, "full_access", "default_native", empty(), "InternalScrollSearchRequest")
.expect("access_denied", SQL_ACTION_NAME, "full_access", "default_native", empty(), "InternalScrollSearchRequest")
.expect("access_denied", SQL_ACTION_NAME, "full_access", "default_native", empty(), "InternalScrollSearchRequest")
.expect("access_denied", SQL_ACTION_NAME, "full_access", "default_native", empty(), "InternalScrollSearchRequest")
.expect("access_denied", SQL_ACTION_NAME, "full_access", "default_native", empty(), "InternalScrollSearchRequest")
.assertLogs();
}
protected class RestAuditLogAsserter extends AuditLogAsserter {
@Override
public AuditLogAsserter expect(String eventType, String action, String principal, String realm,
Matcher<? extends Iterable<? extends String>> indicesMatcher, String request) {
final Matcher<String> runByPrincipalMatcher = principal.equals("test_admin") ? Matchers.nullValue(String.class)
: Matchers.is("test_admin");
final Matcher<String> runByRealmMatcher = realm.equals("default_file") ? Matchers.nullValue(String.class)
: Matchers.is("default_file");
logCheckers.add(
m -> eventType.equals(m.get("event_type"))
&& action.equals(m.get("action"))
&& principal.equals(m.get("principal"))
&& realm.equals(m.get("realm"))
&& runByPrincipalMatcher.matches(m.get("run_by_principal"))
&& runByRealmMatcher.matches(m.get("run_by_realm"))
&& indicesMatcher.matches(m.get("indices"))
&& request.equals(m.get("request")));
return this;
}
}
}

View File

@ -18,6 +18,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.AfterClass;
import org.junit.Before;
@ -192,7 +193,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
public void testQueryWorksAsAdmin() throws Exception {
actions.queryWorksAsAdmin();
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.assertLogs();
}
@ -201,7 +202,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("full_access", actions.minimalPermissionsForAllActions());
actions.expectMatchesAdmin("SELECT * FROM test ORDER BY a", "full_access", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("full_access", "test")
.assertLogs();
@ -211,7 +212,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("full_access", actions.minimalPermissionsForAllActions());
actions.expectScrollMatchesAdmin("SELECT * FROM test ORDER BY a", "full_access", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
/* Scrolling doesn't have to access the index again, at least not through sql.
* If we asserted query and scroll logs then we would see the scroll. */
@ -227,7 +228,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("no_access", "read_nothing");
actions.expectForbidden("no_access", "SELECT * FROM test");
new AuditLogAsserter()
createAuditLogAsserter()
.expect(false, SQL_ACTION_NAME, "no_access", empty())
.assertLogs();
}
@ -236,7 +237,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("wrong_access", "read_something_else");
actions.expectUnknownIndex("wrong_access", "SELECT * FROM test");
new AuditLogAsserter()
createAuditLogAsserter()
//This user has permission to run sql queries so they are given preliminary authorization
.expect(true, SQL_ACTION_NAME, "wrong_access", empty())
//the following get index is granted too but against the no indices placeholder, as ignore_unavailable=true
@ -248,7 +249,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("only_a", "read_test_a");
actions.expectMatchesAdmin("SELECT a FROM test ORDER BY a", "only_a", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("only_a", "test")
.assertLogs();
@ -258,7 +259,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("only_a", "read_test_a");
actions.expectScrollMatchesAdmin("SELECT a FROM test ORDER BY a", "only_a", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
/* Scrolling doesn't have to access the index again, at least not through sql.
* If we asserted query and scroll logs then we would see the scoll. */
@ -280,7 +281,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
* query from the audit side because all the permissions checked
* out but it failed in SQL because it couldn't compile the
* query without the metadata for the missing field. */
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("only_a", "test")
.assertLogs();
}
@ -289,7 +290,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("not_c", "read_test_a_and_b");
actions.expectMatchesAdmin("SELECT a, b FROM test ORDER BY a", "not_c", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("not_c", "test")
.assertLogs();
@ -299,7 +300,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("not_c", "read_test_a_and_b");
actions.expectScrollMatchesAdmin("SELECT a, b FROM test ORDER BY a", "not_c", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
/* Scrolling doesn't have to access the index again, at least not through sql.
* If we asserted query and scroll logs then we would see the scroll. */
@ -321,7 +322,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
* query from the audit side because all the permissions checked
* out but it failed in SQL because it couldn't compile the
* query without the metadata for the missing field. */
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("not_c", "test")
.assertLogs();
}
@ -330,7 +331,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("no_3s", "read_test_without_c_3");
actions.expectMatchesAdmin("SELECT * FROM test WHERE c != 3 ORDER BY a", "no_3s", "SELECT * FROM test ORDER BY a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("no_3s", "test")
.assertLogs();
@ -338,7 +339,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
public void testShowTablesWorksAsAdmin() throws Exception {
actions.expectShowTables(Arrays.asList("bort", "test"), null);
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "bort", "test")
.assertLogs();
}
@ -347,7 +348,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("full_access", actions.minimalPermissionsForAllActions());
actions.expectMatchesAdmin("SHOW TABLES LIKE '%t'", "full_access", "SHOW TABLES");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "bort", "test")
.expectSqlCompositeAction("full_access", "bort", "test")
.assertLogs();
@ -357,7 +358,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("no_access", "read_nothing");
actions.expectForbidden("no_access", "SHOW TABLES");
new AuditLogAsserter()
createAuditLogAsserter()
.expect(false, SQL_ACTION_NAME, "no_access", empty())
.assertLogs();
}
@ -366,7 +367,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("read_bort", "read_bort");
actions.expectMatchesAdmin("SHOW TABLES LIKE 'bort'", "read_bort", "SHOW TABLES");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "bort")
.expectSqlCompositeAction("read_bort", "bort")
.assertLogs();
@ -376,7 +377,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("read_bort", "read_bort");
actions.expectMatchesAdmin("SHOW TABLES LIKE 'not-created'", "read_bort", "SHOW TABLES LIKE 'test'");
new AuditLogAsserter()
createAuditLogAsserter()
.expect(true, SQL_ACTION_NAME, "test_admin", empty())
.expect(true, GetIndexAction.NAME, "test_admin", contains("*", "-*"))
.expect(true, SQL_ACTION_NAME, "read_bort", empty())
@ -390,7 +391,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
expected.put("b", "BIGINT");
expected.put("c", "BIGINT");
actions.expectDescribe(expected, null);
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.assertLogs();
}
@ -399,7 +400,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("full_access", actions.minimalPermissionsForAllActions());
actions.expectMatchesAdmin("DESCRIBE test", "full_access", "DESCRIBE test");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("full_access", "test")
.assertLogs();
@ -409,7 +410,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("no_access", "read_nothing");
actions.expectForbidden("no_access", "DESCRIBE test");
new AuditLogAsserter()
createAuditLogAsserter()
.expect(false, SQL_ACTION_NAME, "no_access", empty())
.assertLogs();
}
@ -418,7 +419,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("wrong_access", "read_something_else");
actions.expectDescribe(Collections.emptyMap(), "wrong_access");
new AuditLogAsserter()
createAuditLogAsserter()
//This user has permission to run sql queries so they are given preliminary authorization
.expect(true, SQL_ACTION_NAME, "wrong_access", empty())
//the following get index is granted too but against the no indices placeholder, as ignore_unavailable=true
@ -430,7 +431,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("only_a", "read_test_a");
actions.expectDescribe(singletonMap("a", "BIGINT"), "only_a");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("only_a", "test")
.assertLogs();
}
@ -442,7 +443,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
expected.put("a", "BIGINT");
expected.put("b", "BIGINT");
actions.expectDescribe(expected, "not_c");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("not_c", "test")
.assertLogs();
}
@ -451,7 +452,7 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
createUser("no_3s", "read_test_without_c_3");
actions.expectMatchesAdmin("DESCRIBE test", "no_3s", "DESCRIBE test");
new AuditLogAsserter()
createAuditLogAsserter()
.expectSqlCompositeAction("test_admin", "test")
.expectSqlCompositeAction("no_3s", "test")
.assertLogs();
@ -480,13 +481,17 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
new StringEntity(Strings.toString(user), ContentType.APPLICATION_JSON));
}
protected AuditLogAsserter createAuditLogAsserter() {
return new AuditLogAsserter();
}
/**
* Used to assert audit logs. Logs are asserted to match in any order because
* we don't always scroll in the same order but each log checker must match a
* single log and all logs must be matched.
*/
protected final class AuditLogAsserter {
private final List<Function<Map<String, Object>, Boolean>> logCheckers = new ArrayList<>();
protected class AuditLogAsserter {
protected final List<Function<Map<String, Object>, Boolean>> logCheckers = new ArrayList<>();
public AuditLogAsserter expectSqlCompositeAction(String user, String... indices) {
expect(true, SQL_ACTION_NAME, user, empty());
@ -507,15 +512,19 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
default:
throw new IllegalArgumentException("Unknown action [" + action + "]");
}
return expect(granted, action, principal, indicesMatcher, request);
final String eventType = granted ? "access_granted" : "access_denied";
final String realm = principal.equals("test_admin") ? "default_file" : "default_native";
return expect(eventType, action, principal, realm, indicesMatcher, request);
}
public AuditLogAsserter expect(boolean granted, String action, String principal,
public AuditLogAsserter expect(String eventType, String action, String principal, String realm,
Matcher<? extends Iterable<? extends String>> indicesMatcher, String request) {
String eventType = granted ? "access_granted" : "access_denied";
logCheckers.add(m -> eventType.equals(m.get("event_type"))
&& action.equals(m.get("action"))
&& principal.equals(m.get("principal"))
&& realm.equals(m.get("realm"))
&& Matchers.nullValue(String.class).matches(m.get("run_by_principal"))
&& Matchers.nullValue(String.class).matches(m.get("run_by_realm"))
&& indicesMatcher.matches(m.get("indices"))
&& request.equals(m.get("request"))
);
@ -543,10 +552,10 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
List<Map<String, Object>> logs = new ArrayList<>();
String line;
Pattern logPattern = Pattern.compile(
("PART PART PART origin_type=PART, origin_address=PART, "
+ "principal=PART, (?:run_as_principal=PART, )?(?:run_by_principal=PART, )?"
("PART PART PART origin_type=PART, origin_address=PART, principal=PART, realm=PART, "
+ "(?:run_as_principal=IGN, )?(?:run_as_realm=IGN, )?(?:run_by_principal=PART, )?(?:run_by_realm=PART, )?"
+ "roles=PART, action=\\[(.*?)\\], (?:indices=PART, )?request=PART")
.replace(" ", "\\s+").replace("PART", "\\[([^\\]]*)\\]"));
.replace(" ", "\\s+").replace("PART", "\\[([^\\]]*)\\]").replace("IGN", "\\[[^\\]]*\\]"));
// fail(logPattern.toString());
while ((line = logReader.readLine()) != null) {
java.util.regex.Matcher m = logPattern.matcher(line);
@ -568,8 +577,9 @@ public abstract class SqlSecurityTestCase extends ESRestTestCase {
log.put("origin_address", m.group(i++));
String principal = m.group(i++);
log.put("principal", principal);
log.put("run_as_principal", m.group(i++));
log.put("realm", m.group(i++));
log.put("run_by_principal", m.group(i++));
log.put("run_by_realm", m.group(i++));
log.put("roles", m.group(i++));
String action = m.group(i++);
if (false == (SQL_ACTION_NAME.equals(action) || GetIndexAction.NAME.equals(action))) {