diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java index 9f206a43c37..287f3ee76f2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java @@ -210,6 +210,10 @@ public class User implements ToXContentObject { output.writeBoolean(false); // last user written, regardless of bwc, does not have an inner user } + public static boolean isInternal(User user) { + return SystemUser.is(user) || XPackUser.is(user) || XPackSecurityUser.is(user) || AsyncSearchUser.is(user); + } + /** Write just the given {@link User}, but not the inner {@link #authenticatedUser}. */ private static void writeUser(User user, StreamOutput output) throws IOException { output.writeBoolean(false); // not a system user diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java index 87621b6ac00..2fb0bc8eeea 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java @@ -35,9 +35,7 @@ import org.elasticsearch.transport.TransportRequest; 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; import org.elasticsearch.xpack.core.security.user.User; -import org.elasticsearch.xpack.core.security.user.XPackUser; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; @@ -446,7 +444,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener { public void accessGranted(String requestId, Authentication authentication, String action, TransportRequest msg, AuthorizationInfo authorizationInfo) { final User user = authentication.getUser(); - final boolean isSystem = SystemUser.is(user) || XPackUser.is(user); + final boolean isSystem = User.isInternal(user); if ((isSystem && events.contains(SYSTEM_ACCESS_GRANTED)) || ((isSystem == false) && events.contains(ACCESS_GRANTED))) { final Optional indices = indices(msg); if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(user), @@ -475,8 +473,7 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener { assert eventType == ACCESS_DENIED || eventType == AuditLevel.ACCESS_GRANTED || eventType == SYSTEM_ACCESS_GRANTED; final String[] indices = index == null ? null : new String[] { index }; final User user = authentication.getUser(); - final boolean isSystem = SystemUser.is(user) || XPackUser.is(user); - if (isSystem && eventType == ACCESS_GRANTED) { + if (User.isInternal(user) && eventType == ACCESS_GRANTED) { eventType = SYSTEM_ACCESS_GRANTED; } if (events.contains(eventType)) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java index f2dc0993c30..0c1a8dc2846 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailTests.java @@ -9,6 +9,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.layout.PatternLayout; import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.bulk.BulkItemRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; @@ -37,8 +38,12 @@ 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.AsyncSearchUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; +import org.elasticsearch.xpack.core.security.user.XPackSecurityUser; +import org.elasticsearch.xpack.core.security.user.XPackUser; +import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.audit.AuditUtil; import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo; @@ -571,11 +576,78 @@ public class LoggingAuditTrailTests extends ESTestCase { assertEmptyLog(logger); } + public void testSystemAccessGranted() throws Exception { + final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext); + final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4)); + final AuthorizationInfo authorizationInfo = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, expectedRoles); + final User systemUser = randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE, XPackSecurityUser.INSTANCE, AsyncSearchUser.INSTANCE); + final Authentication authentication = new Authentication(systemUser, new RealmRef("_reserved", "test", "foo"), null); + final String requestId = randomRequestId(); + + auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo); + // system user + assertEmptyLog(logger); + auditTrail.explicitIndexAccessEvent(requestId, randomFrom(AuditLevel.ACCESS_GRANTED, AuditLevel.SYSTEM_ACCESS_GRANTED), + authentication, "_action", randomFrom(randomAlphaOfLengthBetween(1, 4), null), + BulkItemRequest.class.getName(), + request.remoteAddress(), + authorizationInfo); + // system user + assertEmptyLog(logger); + + // enable system user for access granted events + settings = Settings.builder() + .put(settings) + .put("xpack.security.audit.logfile.events.include", "system_access_granted") + .build(); + auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); + + auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo); + + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted") + .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") + .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName()) + .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); + checkedArrayFields.put(PRINCIPAL_ROLES_FIELD_NAME, (String[]) authorizationInfo.asMap().get(PRINCIPAL_ROLES_FIELD_NAME)); + subject(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + clearLog(); + + String index = randomFrom(randomAlphaOfLengthBetween(1, 4), null); + auditTrail.explicitIndexAccessEvent(requestId, randomFrom(AuditLevel.ACCESS_GRANTED, AuditLevel.SYSTEM_ACCESS_GRANTED), + authentication, "_action", index, BulkItemRequest.class.getName(), request.remoteAddress(), authorizationInfo); + + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted") + .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") + .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, BulkItemRequest.class.getName()) + .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); + checkedArrayFields.put(PRINCIPAL_ROLES_FIELD_NAME, (String[]) authorizationInfo.asMap().get(PRINCIPAL_ROLES_FIELD_NAME)); + subject(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + if (index != null) { + checkedArrayFields.put(LoggingAuditTrail.INDICES_FIELD_NAME, new String[]{index}); + } + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + } + public void testAccessGrantedInternalSystemAction() throws Exception { final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext); final String[] expectedRoles = randomArray(0, 4, String[]::new, () -> randomBoolean() ? null : randomAlphaOfLengthBetween(1, 4)); final AuthorizationInfo authorizationInfo = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, expectedRoles); - final Authentication authentication = new Authentication(SystemUser.INSTANCE, new RealmRef("_reserved", "test", "foo"), null); + final User systemUser = randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE, XPackSecurityUser.INSTANCE, AsyncSearchUser.INSTANCE); + final Authentication authentication = new Authentication(systemUser, new RealmRef("_reserved", "test", "foo"), null); final String requestId = randomRequestId(); auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo); assertEmptyLog(logger); @@ -591,7 +663,7 @@ public class LoggingAuditTrailTests extends ESTestCase { final MapBuilder checkedArrayFields = new MapBuilder<>(); checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_granted") - .put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, SystemUser.INSTANCE.principal()) + .put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, systemUser.principal()) .put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, "_reserved") .put(LoggingAuditTrail.ACTION_FIELD_NAME, "internal:_action") .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName())