From 7ea79c88ab10126c3828aa3b52fd63109ad63b1f Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Sun, 18 Mar 2018 11:27:28 +0200 Subject: [PATCH] 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@cb3801e1975623639e8118c9468cef3f5e7697df --- .../main/resources/security_audit_log.json | 6 + .../action/filter/SecurityActionFilter.java | 4 +- .../BulkShardRequestInterceptor.java | 4 +- ...cumentLevelSecurityRequestInterceptor.java | 5 +- .../IndicesAliasesRequestInterceptor.java | 6 +- .../interceptor/RequestInterceptor.java | 4 +- .../interceptor/ResizeRequestInterceptor.java | 6 +- .../xpack/security/audit/AuditTrail.java | 11 +- .../security/audit/AuditTrailService.java | 21 +- .../security/audit/index/IndexAuditTrail.java | 146 ++++--- .../audit/logfile/LoggingAuditTrail.java | 118 +++--- .../security/authc/AuthenticationService.java | 13 +- .../security/authz/AuthorizationService.java | 32 +- .../SecuritySearchOperationListener.java | 2 +- ...IndicesAliasesRequestInterceptorTests.java | 14 +- .../ResizeRequestInterceptorTests.java | 12 +- .../audit/AuditTrailServiceTests.java | 16 +- .../security/audit/index/AuditTrailTests.java | 23 +- .../index/IndexAuditTrailMutedTests.java | 37 +- .../audit/index/IndexAuditTrailTests.java | 32 +- .../logfile/LoggingAuditTrailFilterTests.java | 322 ++++++++------- .../audit/logfile/LoggingAuditTrailTests.java | 68 ++-- .../authc/AuthenticationServiceTests.java | 4 +- .../authz/AuthorizationServiceTests.java | 376 +++++++++--------- .../SecuritySearchOperationListenerTests.java | 12 +- .../qa/sql/security/RestSqlSecurityIT.java | 45 ++- .../qa/sql/security/SqlSecurityTestCase.java | 76 ++-- 27 files changed, 811 insertions(+), 604 deletions(-) diff --git a/plugin/core/src/main/resources/security_audit_log.json b/plugin/core/src/main/resources/security_audit_log.json index 1a51b5e498c..f3d43fc4895 100644 --- a/plugin/core/src/main/resources/security_audit_log.json +++ b/plugin/core/src/main/resources/security_audit_log.json @@ -69,6 +69,12 @@ "realm": { "type": "keyword" }, + "run_by_realm": { + "type": "keyword" + }, + "run_as_realm": { + "type": "keyword" + }, "transport_profile": { "type": "keyword" }, diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java index 43d9c7d8ea6..448df70b3f5 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java @@ -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); diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkShardRequestInterceptor.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkShardRequestInterceptor.java index de36aa0e672..4e535f10ab5 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkShardRequestInterceptor.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkShardRequestInterceptor.java @@ -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; } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java index 7711bf3277b..ef333ef4855 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java @@ -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 { * If {@link #supports(TransportRequest)} returns true 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. diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptor.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptor.java index f11410f33b7..f259239d873 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptor.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptor.java @@ -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 { @@ -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"); } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java index 852728e750d..3f19d281925 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java @@ -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); } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java index 730990d9e71..1fdfd3db3c3 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java @@ -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); } } } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java index 5e92e4ac751..de5efb042ed 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java @@ -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 indices, TransportMessage message) throws Exception { + private Message message(String type, @Nullable String action, @Nullable User user, @Nullable String[] roleNames, + @Nullable Tuple realms, @Nullable Set 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 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 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 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"; diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java index 379afe72cbc..37381c8994d 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java @@ -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 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 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 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 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; diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java index 3e619e96857..8bae951e883 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java @@ -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); } diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 9fb6e233f84..8ab48a03206 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -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 diff --git a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListener.java b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListener.java index 8e4070439a7..e3121c9512d 100644 --- a/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListener.java +++ b/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListener.java @@ -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); } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/IndicesAliasesRequestInterceptorTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/IndicesAliasesRequestInterceptorTests.java index 5a14d02641a..176196b2845 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/IndicesAliasesRequestInterceptorTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/IndicesAliasesRequestInterceptorTests.java @@ -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); } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptorTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptorTests.java index 0cf0a6716de..787108ccd32 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptorTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/interceptor/ResizeRequestInterceptorTests.java @@ -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); } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java index 83d8a43ddf7..13a7e5c3cf7 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java @@ -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()])); diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java index 599e8e7adf1..e64d9bb7e44 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java @@ -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 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> waitForAuditEvents() throws InterruptedException { waitForAuditTrailToBeWritten(); - AtomicReference>> eventsRef = new AtomicReference<>(); + final AtomicReference>> eventsRef = new AtomicReference<>(); awaitBusy(() -> { try { final Collection> 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> 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>> listener = new PlainActionFuture(); + final PlainActionFuture>> listener = new PlainActionFuture(); ScrollHelper.fetchAllByEntity(client, request, listener, SearchHit::getSourceAsMap); return listener.get(); diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java index 863bd2229b3..33ba5741e08 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailMutedTests.java @@ -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() { diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java index a91950dc765..a1e8cc3c4e9 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java @@ -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) 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 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) 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 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 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) 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 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); + } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java index 9528d8c0462..4c9df8fd9d3 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java @@ -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> settingsList = new ArrayList<>(); LoggingAuditTrail.registerSettings(settingsList); @@ -1593,4 +1649,4 @@ public class LoggingAuditTrailFilterTests extends ESTestCase { } -} \ No newline at end of file +} diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java index bf19fb73850..408d3e797e5 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java @@ -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> settingsList = new ArrayList<>(); LoggingAuditTrail.registerSettings(settingsList); diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index 91c18a47f82..4670e7df086 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -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); } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index e7395f64a1e..3013a7c41c2 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -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 request = randomCompositeRequest(); - authorize(createAuthentication(user), request.v1(), request.v2()); + final Authentication authentication = createAuthentication(new ElasticUser(true)); + final Tuple 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 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 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 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 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 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 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 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 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() }); } } diff --git a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListenerTests.java b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListenerTests.java index 8ce0a5ce1a0..91d61e1ca5c 100644 --- a/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListenerTests.java +++ b/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/SecuritySearchOperationListenerTests.java @@ -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 { diff --git a/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/RestSqlSecurityIT.java b/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/RestSqlSecurityIT.java index 478e6fe0edc..6ac1c2c11ea 100644 --- a/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/RestSqlSecurityIT.java +++ b/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/RestSqlSecurityIT.java @@ -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> indicesMatcher, String request) { + final Matcher runByPrincipalMatcher = principal.equals("test_admin") ? Matchers.nullValue(String.class) + : Matchers.is("test_admin"); + final Matcher 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; + } + + } } diff --git a/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/SqlSecurityTestCase.java b/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/SqlSecurityTestCase.java index 70aa32d4b91..f9ffa14f6d3 100644 --- a/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/SqlSecurityTestCase.java +++ b/qa/sql/security/src/test/java/org/elasticsearch/xpack/qa/sql/security/SqlSecurityTestCase.java @@ -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, Boolean>> logCheckers = new ArrayList<>(); + protected class AuditLogAsserter { + protected final List, 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> 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> 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))) {