diff --git a/x-pack/plugin/core/src/main/config/log4j2.properties b/x-pack/plugin/core/src/main/config/log4j2.properties index c37faf84afbea..2b9b29bc88112 100644 --- a/x-pack/plugin/core/src/main/config/log4j2.properties +++ b/x-pack/plugin/core/src/main/config/log4j2.properties @@ -17,8 +17,11 @@ appender.audit_rolling.layout.pattern = {\ %varsNotEmpty{, "user.realm":"%enc{%map{user.realm}}{JSON}"}\ %varsNotEmpty{, "user.run_by.realm":"%enc{%map{user.run_by.realm}}{JSON}"}\ %varsNotEmpty{, "user.run_as.realm":"%enc{%map{user.run_as.realm}}{JSON}"}\ + %varsNotEmpty{, "apikey.id":"%enc{%map{apikey.id}}{JSON}"}\ + %varsNotEmpty{, "apikey.name":"%enc{%map{apikey.name}}{JSON}"}\ %varsNotEmpty{, "user.roles":%map{user.roles}}\ %varsNotEmpty{, "origin.type":"%enc{%map{origin.type}}{JSON}"}\ + %varsNotEmpty{, "authentication.type":"%enc{%map{authentication.type}}{JSON}"}\ %varsNotEmpty{, "origin.address":"%enc{%map{origin.address}}{JSON}"}\ %varsNotEmpty{, "realm":"%enc{%map{realm}}{JSON}"}\ %varsNotEmpty{, "url.path":"%enc{%map{url.path}}{JSON}"}\ diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java index 8445238738d5b..432b80578c76f 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrail.java @@ -10,7 +10,6 @@ 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.user.User; import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; @@ -22,9 +21,9 @@ public interface AuditTrail { String name(); - void authenticationSuccess(String requestId, String realm, User user, RestRequest request); + void authenticationSuccess(String requestId, Authentication authentication, RestRequest request); - void authenticationSuccess(String requestId, String realm, User user, String action, TransportRequest transportRequest); + void authenticationSuccess(String requestId, Authentication authentication, String action, TransportRequest transportRequest); void anonymousAccessDenied(String requestId, String action, TransportRequest transportRequest); @@ -52,7 +51,7 @@ void accessDenied(String requestId, Authentication authentication, String action void tamperedRequest(String requestId, String action, TransportRequest transportRequest); - void tamperedRequest(String requestId, User user, String action, TransportRequest transportRequest); + void tamperedRequest(String requestId, Authentication authentication, String action, TransportRequest transportRequest); /** * The {@link #connectionGranted(InetAddress, String, SecurityIpFilterRule)} and diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java index 018f88cfdf38e..4449cfca8190e 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java @@ -12,7 +12,6 @@ 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.user.User; import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; @@ -54,10 +53,11 @@ public String name() { } @Override - public void authenticationSuccess(String requestId, String realm, User user, RestRequest request) {} + public void authenticationSuccess(String requestId, Authentication authentication, RestRequest request) {} @Override - public void authenticationSuccess(String requestId, String realm, User user, String action, TransportRequest transportRequest) {} + public void authenticationSuccess(String requestId, Authentication authentication, String action, + TransportRequest transportRequest) {} @Override public void anonymousAccessDenied(String requestId, String action, TransportRequest transportRequest) {} @@ -99,7 +99,7 @@ public void tamperedRequest(String requestId, RestRequest request) {} public void tamperedRequest(String requestId, String action, TransportRequest transportRequest) {} @Override - public void tamperedRequest(String requestId, User user, String action, TransportRequest transportRequest) {} + public void tamperedRequest(String requestId, Authentication authentication, String action, TransportRequest transportRequest) {} @Override public void connectionGranted(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {} @@ -143,16 +143,17 @@ public String name() { } @Override - public void authenticationSuccess(String requestId, String realm, User user, RestRequest request) { + public void authenticationSuccess(String requestId, Authentication authentication, RestRequest request) { for (AuditTrail auditTrail : auditTrails) { - auditTrail.authenticationSuccess(requestId, realm, user, request); + auditTrail.authenticationSuccess(requestId, authentication, request); } } @Override - public void authenticationSuccess(String requestId, String realm, User user, String action, TransportRequest transportRequest) { + public void authenticationSuccess(String requestId, Authentication authentication, String action, + TransportRequest transportRequest) { for (AuditTrail auditTrail : auditTrails) { - auditTrail.authenticationSuccess(requestId, realm, user, action, transportRequest); + auditTrail.authenticationSuccess(requestId, authentication, action, transportRequest); } } @@ -244,9 +245,9 @@ public void tamperedRequest(String requestId, String action, TransportRequest tr } @Override - public void tamperedRequest(String requestId, User user, String action, TransportRequest transportRequest) { + public void tamperedRequest(String requestId, Authentication authentication, String action, TransportRequest transportRequest) { for (AuditTrail auditTrail : auditTrails) { - auditTrail.tamperedRequest(requestId, user, action, transportRequest); + auditTrail.tamperedRequest(requestId, authentication, action, transportRequest); } } 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 2fb0bc8eeea37..e0a5540844412 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 @@ -34,12 +34,13 @@ 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.authz.AuthorizationEngine.AuthorizationInfo; import org.elasticsearch.xpack.core.security.support.Automatons; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; -import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo; +import org.elasticsearch.xpack.security.authc.ApiKeyService; import org.elasticsearch.xpack.security.rest.RemoteHostHeader; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; @@ -106,7 +107,10 @@ public class LoggingAuditTrail implements AuditTrail, ClusterStateListener { public static final String PRINCIPAL_REALM_FIELD_NAME = "user.realm"; public static final String PRINCIPAL_RUN_BY_REALM_FIELD_NAME = "user.run_by.realm"; public static final String PRINCIPAL_RUN_AS_REALM_FIELD_NAME = "user.run_as.realm"; + public static final String API_KEY_ID_FIELD_NAME = "apikey.id"; + public static final String API_KEY_NAME_FIELD_NAME = "apikey.name"; public static final String PRINCIPAL_ROLES_FIELD_NAME = "user.roles"; + public static final String AUTHENTICATION_TYPE_FIELD_NAME = "authentication.type"; public static final String REALM_FIELD_NAME = "realm"; public static final String URL_PATH_FIELD_NAME = "url.path"; public static final String URL_QUERY_FIELD_NAME = "url.query"; @@ -231,16 +235,22 @@ public LoggingAuditTrail(Settings settings, ClusterService clusterService, Threa } @Override - public void authenticationSuccess(String requestId, String realm, User user, RestRequest request) { + public void authenticationSuccess(String requestId, Authentication authentication, RestRequest request) { if (events.contains(AUTHENTICATION_SUCCESS) && eventFilterPolicyRegistry.ignorePredicate() - .test(new AuditEventMetaInfo(Optional.of(user), Optional.of(realm), Optional.empty(), Optional.empty())) == false) { + .test(new AuditEventMetaInfo( + Optional.of(authentication.getUser()), + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), + Optional.empty(), + Optional.empty())) == false) { + // this is redundant information maintained for bwc purposes + final String authnRealm = authentication.getAuthenticatedBy().getName(); final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, REST_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "authentication_success") - .with(REALM_FIELD_NAME, realm) + .with(REALM_FIELD_NAME, authnRealm) .withRestUriAndMethod(request) .withRequestId(requestId) - .withPrincipal(user) + .withAuthentication(authentication) .withRestOrigin(request) .withRequestBody(request) .withOpaqueId(threadContext) @@ -251,19 +261,22 @@ public void authenticationSuccess(String requestId, String realm, User user, Res } @Override - public void authenticationSuccess(String requestId, String realm, User user, String action, TransportRequest transportRequest) { + public void authenticationSuccess(String requestId, Authentication authentication, String action, TransportRequest transportRequest) { if (events.contains(AUTHENTICATION_SUCCESS)) { final Optional indices = indices(transportRequest); if (eventFilterPolicyRegistry.ignorePredicate() - .test(new AuditEventMetaInfo(Optional.of(user), Optional.of(realm), Optional.empty(), indices)) == false) { + .test(new AuditEventMetaInfo( + Optional.of(authentication.getUser()), + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), + Optional.empty(), + indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "authentication_success") - .with(REALM_FIELD_NAME, realm) .with(ACTION_FIELD_NAME, action) .with(REQUEST_NAME_FIELD_NAME, transportRequest.getClass().getSimpleName()) .withRequestId(requestId) - .withPrincipal(user) + .withAuthentication(authentication) .withRestOrTransportOrigin(transportRequest, threadContext) .with(INDICES_FIELD_NAME, indices.orElse(null)) .withOpaqueId(threadContext) @@ -448,14 +461,14 @@ public void accessGranted(String requestId, Authentication authentication, Strin 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), - Optional.of(effectiveRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "access_granted") .with(ACTION_FIELD_NAME, action) .with(REQUEST_NAME_FIELD_NAME, msg.getClass().getSimpleName()) .withRequestId(requestId) - .withSubject(authentication) + .withAuthentication(authentication) .withRestOrTransportOrigin(msg, threadContext) .with(INDICES_FIELD_NAME, indices.orElse(null)) .withOpaqueId(threadContext) @@ -478,7 +491,7 @@ public void explicitIndexAccessEvent(String requestId, AuditLevel eventType, Aut } if (events.contains(eventType)) { if (eventFilterPolicyRegistry.ignorePredicate() - .test(new AuditEventMetaInfo(Optional.of(user), Optional.of(effectiveRealmName(authentication)), + .test(new AuditEventMetaInfo(Optional.of(user), Optional.of(ApiKeyService.getCreatorRealmName(authentication)), Optional.of(authorizationInfo), Optional.ofNullable(indices))) == false) { final LogEntryBuilder logEntryBuilder = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) @@ -486,7 +499,7 @@ public void explicitIndexAccessEvent(String requestId, AuditLevel eventType, Aut .with(ACTION_FIELD_NAME, action) .with(REQUEST_NAME_FIELD_NAME, requestName) .withRequestId(requestId) - .withSubject(authentication) + .withAuthentication(authentication) .with(INDICES_FIELD_NAME, indices) .withOpaqueId(threadContext) .withXForwardedFor(threadContext) @@ -512,14 +525,14 @@ public void accessDenied(String requestId, Authentication authentication, String if (events.contains(ACCESS_DENIED)) { final Optional indices = indices(transportRequest); if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()), - Optional.of(effectiveRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "access_denied") .with(ACTION_FIELD_NAME, action) .with(REQUEST_NAME_FIELD_NAME, transportRequest.getClass().getSimpleName()) .withRequestId(requestId) - .withSubject(authentication) + .withAuthentication(authentication) .withRestOrTransportOrigin(transportRequest, threadContext) .with(INDICES_FIELD_NAME, indices.orElse(null)) .with(authorizationInfo.asMap()) @@ -571,11 +584,14 @@ public void tamperedRequest(String requestId, String action, TransportRequest tr } @Override - public void tamperedRequest(String requestId, User user, String action, TransportRequest transportRequest) { + public void tamperedRequest(String requestId, Authentication authentication, String action, TransportRequest transportRequest) { if (events.contains(TAMPERED_REQUEST)) { final Optional indices = indices(transportRequest); - if (eventFilterPolicyRegistry.ignorePredicate() - .test(new AuditEventMetaInfo(Optional.of(user), Optional.empty(), Optional.empty(), indices)) == false) { + if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo( + Optional.of(authentication.getUser()), + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), + Optional.empty(), + indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "tampered_request") @@ -583,7 +599,7 @@ public void tamperedRequest(String requestId, User user, String action, Transpor .with(REQUEST_NAME_FIELD_NAME, transportRequest.getClass().getSimpleName()) .withRequestId(requestId) .withRestOrTransportOrigin(transportRequest, threadContext) - .withPrincipal(user) + .withAuthentication(authentication) .with(INDICES_FIELD_NAME, indices.orElse(null)) .withOpaqueId(threadContext) .withXForwardedFor(threadContext) @@ -635,7 +651,7 @@ public void runAsGranted(String requestId, Authentication authentication, String if (events.contains(RUN_AS_GRANTED)) { final Optional indices = indices(transportRequest); if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()), - Optional.of(effectiveRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "run_as_granted") @@ -660,7 +676,7 @@ public void runAsDenied(String requestId, Authentication authentication, String if (events.contains(RUN_AS_DENIED)) { final Optional indices = indices(transportRequest); if (eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()), - Optional.of(effectiveRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), Optional.of(authorizationInfo), indices)) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, TRANSPORT_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "run_as_denied") @@ -681,9 +697,10 @@ public void runAsDenied(String requestId, Authentication authentication, String @Override public void runAsDenied(String requestId, Authentication authentication, RestRequest request, AuthorizationInfo authorizationInfo) { - if (events.contains(RUN_AS_DENIED) - && eventFilterPolicyRegistry.ignorePredicate().test(new AuditEventMetaInfo(Optional.of(authentication.getUser()), - Optional.of(effectiveRealmName(authentication)), Optional.of(authorizationInfo), Optional.empty())) == false) { + if (events.contains(RUN_AS_DENIED) && eventFilterPolicyRegistry.ignorePredicate().test( + new AuditEventMetaInfo(Optional.of(authentication.getUser()), + Optional.of(ApiKeyService.getCreatorRealmName(authentication)), + Optional.of(authorizationInfo), Optional.empty())) == false) { final StringMapMessage logEntry = new LogEntryBuilder() .with(EVENT_TYPE_FIELD_NAME, REST_ORIGIN_FIELD_VALUE) .with(EVENT_ACTION_FIELD_NAME, "run_as_denied") @@ -797,22 +814,22 @@ LogEntryBuilder withXForwardedFor(ThreadContext threadContext) { return this; } - LogEntryBuilder withPrincipal(User user) { - logEntry.with(PRINCIPAL_FIELD_NAME, user.principal()); - if (user.isRunAs()) { - logEntry.with(PRINCIPAL_RUN_BY_FIELD_NAME, user.authenticatedUser().principal()); - } - return this; - } - - LogEntryBuilder withSubject(Authentication authentication) { + LogEntryBuilder withAuthentication(Authentication authentication) { logEntry.with(PRINCIPAL_FIELD_NAME, authentication.getUser().principal()); - if (authentication.getUser().isRunAs()) { - logEntry.with(PRINCIPAL_REALM_FIELD_NAME, authentication.getLookedUpBy().getName()) - .with(PRINCIPAL_RUN_BY_FIELD_NAME, authentication.getUser().authenticatedUser().principal()) - .with(PRINCIPAL_RUN_BY_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + logEntry.with(AUTHENTICATION_TYPE_FIELD_NAME, authentication.getAuthenticationType().toString()); + if (Authentication.AuthenticationType.API_KEY == authentication.getAuthenticationType()) { + logEntry.with(API_KEY_ID_FIELD_NAME, (String) authentication.getMetadata().get(ApiKeyService.API_KEY_ID_KEY)) + .with(API_KEY_NAME_FIELD_NAME, (String) authentication.getMetadata().get(ApiKeyService.API_KEY_NAME_KEY)) + .with(PRINCIPAL_REALM_FIELD_NAME, + (String) authentication.getMetadata().get(ApiKeyService.API_KEY_CREATOR_REALM_NAME)); } else { - logEntry.with(PRINCIPAL_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + if (authentication.getUser().isRunAs()) { + logEntry.with(PRINCIPAL_REALM_FIELD_NAME, authentication.getLookedUpBy().getName()) + .with(PRINCIPAL_RUN_BY_FIELD_NAME, authentication.getUser().authenticatedUser().principal()) + .with(PRINCIPAL_RUN_BY_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + } else { + logEntry.with(PRINCIPAL_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + } } return this; } @@ -878,11 +895,6 @@ private static Optional indices(TransportRequest transportRequest) { return Optional.empty(); } - private static String effectiveRealmName(Authentication authentication) { - return authentication.getLookedUpBy() != null ? authentication.getLookedUpBy().getName() - : authentication.getAuthenticatedBy().getName(); - } - public static void registerSettings(List> settings) { settings.add(EMIT_HOST_ADDRESS_SETTING); settings.add(EMIT_HOST_NAME_SETTING); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java index b1b40d9aada6b..8d08a0dba5862 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java @@ -675,13 +675,13 @@ void finishAuthentication(User finalUser) { * successful */ void writeAuthToContext(Authentication authentication) { - request.authenticationSuccess(authentication.getAuthenticatedBy().getName(), authentication.getUser()); Runnable action = () -> { logger.trace("Established authentication [{}] for request [{}]", authentication, request); listener.onResponse(authentication); }; try { authenticationSerializer.writeToContext(authentication, threadContext); + request.authenticationSuccess(authentication); } catch (Exception e) { action = () -> { logger.debug( @@ -724,7 +724,7 @@ abstract static class AuditableRequest { abstract ElasticsearchSecurityException runAsDenied(Authentication authentication, AuthenticationToken token); - abstract void authenticationSuccess(String realm, User user); + abstract void authenticationSuccess(Authentication authentication); } @@ -744,8 +744,8 @@ static class AuditableTransportRequest extends AuditableRequest { } @Override - void authenticationSuccess(String realm, User user) { - auditTrail.authenticationSuccess(requestId, realm, user, action, transportRequest); + void authenticationSuccess(Authentication authentication) { + auditTrail.authenticationSuccess(requestId, authentication, action, transportRequest); } @Override @@ -808,8 +808,8 @@ static class AuditableRestRequest extends AuditableRequest { } @Override - void authenticationSuccess(String realm, User user) { - auditTrail.authenticationSuccess(requestId, realm, user, request); + void authenticationSuccess(Authentication authentication) { + auditTrail.authenticationSuccess(requestId, authentication, request); } @Override diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 569ecaa7f0498..55f47e173c8dd 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -176,7 +176,7 @@ public void authorize(final Authentication authentication, final String action, if (isInternalUser(authentication.getUser()) != false) { auditId = AuditUtil.getOrGenerateRequestId(threadContext); } else { - auditTrailService.get().tamperedRequest(null, authentication.getUser(), action, originalRequest); + auditTrailService.get().tamperedRequest(null, authentication, action, originalRequest); final String message = "Attempt to authorize action [" + action + "] for [" + authentication.getUser().principal() + "] without an existing request-id"; assert false : message; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java index 58f43a11d3a40..005dfb71e7129 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java @@ -13,8 +13,8 @@ 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.core.security.authz.AuthorizationEngine.AuthorizationInfo; +import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; import org.junit.Before; @@ -212,14 +212,14 @@ public void testConnectionDenied() throws Exception { } public void testAuthenticationSuccessRest() throws Exception { - User user = new User("_username", "r1"); - String realm = "_realm"; + Authentication authentication = new Authentication(new User("_username", "r1"), new RealmRef("_realm", null, null), + new RealmRef(null, null, null)); final String requestId = randomAlphaOfLengthBetween(6, 12); - service.get().authenticationSuccess(requestId, realm, user, restRequest); + service.get().authenticationSuccess(requestId, authentication, restRequest); verify(licenseState).checkFeature(Feature.SECURITY_AUDITING); if (isAuditingAllowed) { for (AuditTrail auditTrail : auditTrails) { - verify(auditTrail).authenticationSuccess(requestId, realm, user, restRequest); + verify(auditTrail).authenticationSuccess(requestId, authentication, restRequest); } } else { verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()])); @@ -227,14 +227,14 @@ public void testAuthenticationSuccessRest() throws Exception { } public void testAuthenticationSuccessTransport() throws Exception { - User user = new User("_username", "r1"); - String realm = "_realm"; + Authentication authentication = new Authentication(new User("_username", "r1"), new RealmRef("_realm", null, null), + new RealmRef(null, null, null)); final String requestId = randomAlphaOfLengthBetween(6, 12); - service.get().authenticationSuccess(requestId, realm, user, "_action", request); + service.get().authenticationSuccess(requestId, authentication, "_action", request); verify(licenseState).checkFeature(Feature.SECURITY_AUDITING); if (isAuditingAllowed) { for (AuditTrail auditTrail : auditTrails) { - verify(auditTrail).authenticationSuccess(requestId, realm, user, "_action", request); + verify(auditTrail).authenticationSuccess(requestId, authentication, "_action", request); } } else { verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()])); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java index 295c097e29a65..a11079f720f65 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrailFilterTests.java @@ -8,6 +8,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.Client; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; @@ -17,11 +18,13 @@ import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.mock.orig.Mockito; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.test.rest.FakeRestRequest.Builder; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.xpack.core.security.audit.logfile.CapturingLogger; import org.elasticsearch.xpack.core.security.authc.Authentication; @@ -33,7 +36,9 @@ import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.AuditEventMetaInfo; import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrailTests.MockRequest; import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrailTests.RestContent; +import org.elasticsearch.xpack.security.authc.ApiKeyService; import org.elasticsearch.xpack.security.rest.RemoteHostHeader; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; import org.junit.Before; import org.mockito.stubbing.Answer; @@ -41,6 +46,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.time.Clock; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -49,6 +55,7 @@ import java.util.stream.Collectors; import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME; +import static org.elasticsearch.xpack.security.authc.ApiKeyServiceTests.Utils.createApiKeyAuthentication; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -61,6 +68,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase { private Settings settings; private DiscoveryNode localNode; private ClusterService clusterService; + private ApiKeyService apiKeyService; @Before public void init() throws Exception { @@ -82,6 +90,8 @@ public void init() throws Exception { arg0.updateLocalNodeInfo(localNode); return null; }).when(clusterService).addListener(Mockito.isA(LoggingAuditTrail.class)); + apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), mock(Client.class), new XPackLicenseState(settings), + mock(SecurityIndexManager.class), clusterService, mock(ThreadPool.class)); } public void testPolicyDoesNotMatchNullValuesInEvent() throws Exception { @@ -463,7 +473,7 @@ public void testUsersFilter() throws Exception { Collections.emptyList()); } } - final Authentication filteredAuthentication; + Authentication filteredAuthentication; if (randomBoolean()) { filteredAuthentication = createAuthentication( new User(randomFrom(allFilteredUsers), new String[] { "r1" }, new User("authUsername", new String[] { "r2" })), @@ -472,7 +482,10 @@ public void testUsersFilter() throws Exception { filteredAuthentication = createAuthentication(new User(randomFrom(allFilteredUsers), new String[] { "r1" }), "effectiveRealmName"); } - final Authentication unfilteredAuthentication; + if (randomBoolean()) { + filteredAuthentication = createApiKeyAuthentication(apiKeyService, filteredAuthentication); + } + Authentication unfilteredAuthentication; if (randomBoolean()) { unfilteredAuthentication = createAuthentication(new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4), new String[] { "r1" }, new User("authUsername", new String[] { "r2" })), "effectiveRealmName"); @@ -480,6 +493,9 @@ public void testUsersFilter() throws Exception { unfilteredAuthentication = createAuthentication( new User(UNFILTER_MARKER + randomAlphaOfLengthBetween(1, 4), new String[] { "r1" }), "effectiveRealmName"); } + if (randomBoolean()) { + unfilteredAuthentication = createApiKeyAuthentication(apiKeyService, unfilteredAuthentication); + } final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext, new String[] { "idx1", "idx2" }); final MockToken filteredToken = new MockToken(randomFrom(allFilteredUsers)); @@ -644,12 +660,12 @@ public void testUsersFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.tamperedRequest(randomAlphaOfLength(8), unfilteredAuthentication.getUser(), "_action", request); + auditTrail.tamperedRequest(randomAlphaOfLength(8), unfilteredAuthentication, "_action", request); assertThat("Tampered message: unfiltered user is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); - auditTrail.tamperedRequest(randomAlphaOfLength(8), filteredAuthentication.getUser(), "_action", request); + auditTrail.tamperedRequest(randomAlphaOfLength(8), filteredAuthentication, "_action", request); assertThat("Tampered message: filtered user is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); @@ -711,22 +727,22 @@ public void testUsersFilter() throws Exception { threadContext.stashContext(); // authentication Success - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", unfilteredAuthentication.getUser(), getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), unfilteredAuthentication, getRestRequest()); assertThat("AuthenticationSuccess rest request: unfiltered user is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", filteredAuthentication.getUser(), getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), filteredAuthentication, getRestRequest()); assertThat("AuthenticationSuccess rest request: filtered user is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", unfilteredAuthentication.getUser(), "_action", request); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), unfilteredAuthentication, "_action", request); assertThat("AuthenticationSuccess message: unfiltered user is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", filteredAuthentication.getUser(), "_action", request); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), filteredAuthentication, "_action", request); assertThat("AuthenticationSuccess message: filtered user is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); @@ -849,14 +865,18 @@ public void testRealmsFilter() throws Exception { threadContext.stashContext(); // accessGranted - auditTrail.accessGranted(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), "_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessGranted(randomAlphaOfLength(8), + randomBoolean() ? createAuthentication(user, filteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, filteredRealm)), + "_action", request, authzInfo(new String[]{"role1"})); assertThat("AccessGranted message: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.accessGranted(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), "_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessGranted(randomAlphaOfLength(8), + randomBoolean() ? createAuthentication(user, unfilteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, unfilteredRealm)), + "_action", request, authzInfo(new String[]{"role1"})); assertThat("AccessGranted message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); @@ -873,27 +893,31 @@ public void testRealmsFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.accessGranted(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), "internal:_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessGranted(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, filteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, filteredRealm)), + "internal:_action", request, authzInfo(new String[]{"role1"})); assertThat("AccessGranted internal message: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.accessGranted(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), "internal:_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessGranted(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, unfilteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, unfilteredRealm)), + "internal:_action", request, authzInfo(new String[] { "role1" })); assertThat("AccessGranted internal message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); // accessDenied - auditTrail.accessDenied(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), "_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessDenied(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, filteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, filteredRealm)), "_action", request, + authzInfo(new String[]{"role1"})); assertThat("AccessDenied message: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.accessDenied(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), "_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessDenied(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, unfilteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, unfilteredRealm)), "_action", request, + authzInfo(new String[]{"role1"})); assertThat("AccessDenied message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); @@ -910,14 +934,16 @@ public void testRealmsFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.accessDenied(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), "internal:_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessDenied(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, filteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, filteredRealm)), "internal:_action", + request, authzInfo(new String[]{"role1"})); assertThat("AccessGranted internal message: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.accessDenied(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), "internal:_action", request, - authzInfo(new String[] { "role1" })); + auditTrail.accessDenied(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, unfilteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, unfilteredRealm)), "internal:_action", + request, authzInfo(new String[]{"role1"})); assertThat("AccessGranted internal message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); @@ -941,12 +967,15 @@ public void testRealmsFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.tamperedRequest(randomAlphaOfLength(8), user, "_action", request); - if (filterMissingRealm) { - assertThat("Tampered message: is not filtered out by the missing realm filter", logOutput.size(), is(0)); - } else { - assertThat("Tampered message: is filtered out", logOutput.size(), is(1)); - } + auditTrail.tamperedRequest(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, filteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, filteredRealm)), "_action", request); + assertThat("Tampered message: filtered realm is not filtered out", logOutput.size(), is(0)); + logOutput.clear(); + threadContext.stashContext(); + + auditTrail.tamperedRequest(randomAlphaOfLength(8), randomBoolean() ? createAuthentication(user, unfilteredRealm) : + createApiKeyAuthentication(apiKeyService, createAuthentication(user, unfilteredRealm)), "_action", request); + assertThat("Tampered message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); @@ -1009,22 +1038,22 @@ public void testRealmsFilter() throws Exception { threadContext.stashContext(); // authentication Success - auditTrail.authenticationSuccess(randomAlphaOfLength(8), unfilteredRealm, user, getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), getRestRequest()); assertThat("AuthenticationSuccess rest request: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), filteredRealm, user, getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), getRestRequest()); assertThat("AuthenticationSuccess rest request: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), unfilteredRealm, user, "_action", request); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), createAuthentication(user, unfilteredRealm), "_action", request); assertThat("AuthenticationSuccess message: unfiltered realm is filtered out", logOutput.size(), is(1)); logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), filteredRealm, user, "_action", request); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), createAuthentication(user, filteredRealm), "_action", request); assertThat("AuthenticationSuccess message: filtered realm is not filtered out", logOutput.size(), is(0)); logOutput.clear(); threadContext.stashContext(); @@ -1079,13 +1108,16 @@ public void testRolesFilter() throws Exception { settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.otherPolicy.roles", otherRoles); } final String[] unfilteredRoles = _unfilteredRoles.toArray(new String[0]); - final Authentication authentication; + Authentication authentication; if (randomBoolean()) { authentication = createAuthentication(new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" })), "effectiveRealmName"); } else { authentication = createAuthentication(new User("user1", new String[] { "r1" }), "effectiveRealmName"); } + if (randomBoolean()) { + authentication = createApiKeyAuthentication(apiKeyService, authentication); + } final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext, new String[] { "idx1", "idx2" }); final MockToken authToken = new MockToken("token1"); @@ -1288,7 +1320,7 @@ public void testRolesFilter() throws Exception { threadContext.stashContext(); // authentication Success - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", authentication.getUser(), getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, getRestRequest()); if (filterMissingRoles) { assertThat("AuthenticationSuccess rest request: is not filtered out by the missing roles filter", logOutput.size(), is(0)); } else { @@ -1297,7 +1329,7 @@ public void testRolesFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", authentication.getUser(), "_action", request); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, "_action", request); if (filterMissingRoles) { assertThat("AuthenticationSuccess message: is not filtered out by the missing roles filter", logOutput.size(), is(0)); } else { @@ -1356,13 +1388,16 @@ public void testIndicesFilter() throws Exception { settingsBuilder.putList("xpack.security.audit.logfile.events.ignore_filters.otherPolicy.indices", otherIndices); } final String[] unfilteredIndices = _unfilteredIndices.toArray(new String[0]); - final Authentication authentication; + Authentication authentication; if (randomBoolean()) { authentication = createAuthentication(new User("user1", new String[] { "r1" }, new User("authUsername", new String[] { "r2" })), "effectiveRealmName"); } else { authentication = createAuthentication(new User("user1", new String[] { "r1" }), "effectiveRealmName"); } + if (randomBoolean()) { + authentication = createApiKeyAuthentication(apiKeyService, authentication); + } final MockToken authToken = new MockToken("token1"); final TransportRequest noIndexRequest = new MockRequest(threadContext); @@ -1657,7 +1692,7 @@ public void testIndicesFilter() throws Exception { threadContext.stashContext(); // authentication Success - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", authentication.getUser(), getRestRequest()); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, getRestRequest()); if (filterMissingIndices) { assertThat("AuthenticationSuccess rest request: is not filtered out by the missing indices filter", logOutput.size(), is(0)); } else { @@ -1666,7 +1701,7 @@ public void testIndicesFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", authentication.getUser(), "_action", noIndexRequest); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, "_action", noIndexRequest); if (filterMissingIndices) { assertThat("AuthenticationSuccess message no index: not filtered out by missing indices filter", logOutput.size(), is(0)); } else { @@ -1675,13 +1710,13 @@ public void testIndicesFilter() throws Exception { logOutput.clear(); threadContext.stashContext(); - auditTrail.authenticationSuccess(randomAlphaOfLength(8), "_realm", authentication.getUser(), "_action", - new MockIndicesRequest(threadContext, unfilteredIndices)); + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, "_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(randomAlphaOfLength(8), "_realm", authentication.getUser(), "_action", + auditTrail.authenticationSuccess(randomAlphaOfLength(8), authentication, "_action", new MockIndicesRequest(threadContext, filteredIndices)); assertThat("AuthenticationSuccess message filtered indices: not filtered out by indices filter", logOutput.size(), is(0)); logOutput.clear(); 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 0c1a8dc2846c1..521675e6eb5ce 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 @@ -8,9 +8,11 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.layout.PatternLayout; +import org.elasticsearch.Version; import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.action.bulk.BulkItemRequest; import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.Client; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; @@ -27,17 +29,21 @@ import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.mock.orig.Mockito; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.test.rest.FakeRestRequest.Builder; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; 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.AuthenticationType; import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef; import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; +import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo; import org.elasticsearch.xpack.core.security.user.AsyncSearchUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; @@ -46,8 +52,9 @@ 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; +import org.elasticsearch.xpack.security.authc.ApiKeyService; import org.elasticsearch.xpack.security.rest.RemoteHostHeader; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; import org.junit.After; @@ -61,6 +68,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.time.Clock; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -72,6 +80,7 @@ import java.util.regex.Pattern; import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME; +import static org.elasticsearch.xpack.security.authc.ApiKeyServiceTests.Utils.createApiKeyAuthentication; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasToString; @@ -150,6 +159,7 @@ protected String expectedMessage() { private Map commonFields; private Logger logger; private LoggingAuditTrail auditTrail; + private ApiKeyService apiKeyService; @BeforeClass public static void lookupPatternLayout() throws Exception { @@ -188,6 +198,8 @@ public void init() throws Exception { .build(); localNode = mock(DiscoveryNode.class); when(localNode.getAddress()).thenReturn(buildNewFakeTransportAddress()); + Client client = mock(Client.class); + SecurityIndexManager securityIndexManager = mock(SecurityIndexManager.class); clusterService = mock(ClusterService.class); when(clusterService.localNode()).thenReturn(localNode); Mockito.doAnswer((Answer) invocation -> { @@ -208,6 +220,8 @@ public void init() throws Exception { } logger = CapturingLogger.newCapturingLogger(randomFrom(Level.OFF, Level.FATAL, Level.ERROR, Level.WARN, Level.INFO), patternLayout); auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); + apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, new XPackLicenseState(settings), + securityIndexManager, clusterService, mock(ThreadPool.class)); } @After @@ -546,19 +560,39 @@ public void testAccessGranted() 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 = createAuthentication(); final String requestId = randomRequestId(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + Authentication authentication = createAuthentication(); + auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo); + 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)); + authentication(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); auditTrail.accessGranted(requestId, authentication, "_action", request, authorizationInfo); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); - 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.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); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); @@ -612,7 +646,7 @@ public void testSystemAccessGranted() throws Exception { .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); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); @@ -632,7 +666,7 @@ public void testSystemAccessGranted() throws Exception { .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); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); opaqueId(threadContext, checkedFields); forwardedFor(threadContext, checkedFields); @@ -663,6 +697,7 @@ public void testAccessGrantedInternalSystemAction() throws Exception { 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.AUTHENTICATION_TYPE_FIELD_NAME, AuthenticationType.REALM.toString()) .put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, systemUser.principal()) .put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, "_reserved") .put(LoggingAuditTrail.ACTION_FIELD_NAME, "internal:_action") @@ -680,19 +715,39 @@ public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exceptio 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 = createAuthentication(); final String requestId = randomRequestId(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + Authentication authentication = createAuthentication(); auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); - 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.ACTION_FIELD_NAME, "internal:_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); + authentication(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); + auditTrail.accessGranted(requestId, authentication, "internal:_action", request, authorizationInfo); + 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, "internal:_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)); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); @@ -714,24 +769,43 @@ public void testAccessDenied() 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 = createAuthentication(); final String requestId = randomRequestId(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + Authentication authentication = createAuthentication(); auditTrail.accessDenied(requestId, authentication, "_action/bar", request, authorizationInfo); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); - final MapBuilder checkedArrayFields = new MapBuilder<>(); checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_denied") .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action/bar") .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); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); + auditTrail.accessDenied(requestId, authentication, "_action/bar", request, authorizationInfo); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "access_denied") + .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action/bar") + .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)); + authentication(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); // test disabled @@ -814,29 +888,37 @@ public void testTamperedRequest() throws Exception { public void testTamperedRequestWithUser() throws Exception { final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext); - final boolean runAs = randomBoolean(); - final User user; - if (runAs) { - user = new User("running_as", new String[] { "r2" }, new User("_username", new String[] { "r1" })); - } else { - user = new User("_username", new String[] { "r1" }); - } - final String requestId = randomRequestId(); - auditTrail.tamperedRequest(requestId, user, "_action", request); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); - final MapBuilder checkedArrayFields = new MapBuilder<>(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + + Authentication authentication = createAuthentication(); + auditTrail.tamperedRequest(requestId, authentication, "_action", request); checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "tampered_request") .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName()) .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); - if (runAs) { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "running_as"); - checkedFields.put(LoggingAuditTrail.PRINCIPAL_RUN_BY_FIELD_NAME, "_username"); - } else { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "_username"); - } + authentication(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); + auditTrail.tamperedRequest(requestId, authentication, "_action", request); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "tampered_request") + .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") + .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName()) + .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); @@ -850,7 +932,7 @@ public void testTamperedRequestWithUser() throws Exception { .put("xpack.security.audit.logfile.events.exclude", "tampered_request") .build(); auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); - auditTrail.tamperedRequest(requestId, user, "_action", request); + auditTrail.tamperedRequest(requestId, authentication, "_action", request); assertEmptyLog(logger); } @@ -1004,17 +1086,12 @@ public void testAuthenticationSuccessRest() throws Exception { final Tuple tuple = prepareRestContent("_uri", address, params); final String expectedMessage = tuple.v1().expectedMessage(); final RestRequest request = tuple.v2(); - final String realm = randomAlphaOfLengthBetween(1, 6); - final User user; - if (randomBoolean()) { - user = new User("running as", new String[] { "r2" }, new User("_username", new String[] { "r1" })); - } else { - user = new User("_username", new String[] { "r1" }); - } final String requestId = randomRequestId(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + Authentication authentication = createAuthentication(); // event by default disabled - auditTrail.authenticationSuccess(requestId, realm, user, request); + auditTrail.authenticationSuccess(requestId, authentication, request); assertEmptyLog(logger); settings = Settings.builder() @@ -1022,25 +1099,49 @@ public void testAuthenticationSuccessRest() throws Exception { .put("xpack.security.audit.logfile.events.include", "authentication_success") .build(); auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); - auditTrail.authenticationSuccess(requestId, realm, user, request); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); + auditTrail.authenticationSuccess(requestId, authentication, request); checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.REST_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "authentication_success") - .put(LoggingAuditTrail.REALM_FIELD_NAME, realm) + .put(LoggingAuditTrail.REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()) .put(LoggingAuditTrail.ORIGIN_TYPE_FIELD_NAME, LoggingAuditTrail.REST_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(address)) .put(LoggingAuditTrail.REQUEST_METHOD_FIELD_NAME, request.method().toString()) .put(LoggingAuditTrail.REQUEST_BODY_FIELD_NAME, includeRequestBody && Strings.hasLength(expectedMessage) ? expectedMessage : null) .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId) - .put(LoggingAuditTrail.URL_PATH_FIELD_NAME, "_uri") - .put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, params.isEmpty() ? null : "foo=bar&evac=true"); - if (user.isRunAs()) { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "running as"); - checkedFields.put(LoggingAuditTrail.PRINCIPAL_RUN_BY_FIELD_NAME, "_username"); - } else { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "_username"); + .put(LoggingAuditTrail.URL_PATH_FIELD_NAME, "_uri"); + if (includeRequestBody && Strings.hasLength(expectedMessage)) { + checkedFields.put(LoggingAuditTrail.REQUEST_BODY_FIELD_NAME, expectedMessage); + } + if (params.isEmpty() == false) { + checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "foo=bar&evac=true"); + } + authentication(authentication, checkedFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap()); + + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + auditTrail.authenticationSuccess(requestId, authentication, request); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.REST_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "authentication_success") + .put(LoggingAuditTrail.REALM_FIELD_NAME, "_es_api_key") + .put(LoggingAuditTrail.ORIGIN_TYPE_FIELD_NAME, LoggingAuditTrail.REST_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.ORIGIN_ADDRESS_FIELD_NAME, NetworkAddress.format(address)) + .put(LoggingAuditTrail.REQUEST_METHOD_FIELD_NAME, request.method().toString()) + .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId) + .put(LoggingAuditTrail.URL_PATH_FIELD_NAME, "_uri"); + if (includeRequestBody && Strings.hasLength(expectedMessage)) { + checkedFields.put(LoggingAuditTrail.REQUEST_BODY_FIELD_NAME, expectedMessage); } + if (params.isEmpty() == false) { + checkedFields.put(LoggingAuditTrail.URL_QUERY_FIELD_NAME, "foo=bar&evac=true"); + } + authentication(authentication, checkedFields); opaqueId(threadContext, checkedFields); forwardedFor(threadContext, checkedFields); assertMsg(logger, checkedFields.immutableMap()); @@ -1048,17 +1149,13 @@ public void testAuthenticationSuccessRest() throws Exception { public void testAuthenticationSuccessTransport() throws Exception { final TransportRequest request = randomBoolean() ? new MockRequest(threadContext) : new MockIndicesRequest(threadContext); - final User user; - if (randomBoolean()) { - user = new User("running as", new String[] { "r2" }, new User("_username", new String[] { "r1" })); - } else { - user = new User("_username", new String[] { "r1" }); - } - final String realm = randomAlphaOfLengthBetween(1, 6); final String requestId = randomRequestId(); + MapBuilder checkedFields = new MapBuilder<>(commonFields); + MapBuilder checkedArrayFields = new MapBuilder<>(); + Authentication authentication = createAuthentication(); // event by default disabled - auditTrail.authenticationSuccess(requestId, realm, user, "_action", request); + auditTrail.authenticationSuccess(requestId, authentication, "_action", request); assertEmptyLog(logger); settings = Settings.builder() @@ -1066,21 +1163,32 @@ public void testAuthenticationSuccessTransport() throws Exception { .put("xpack.security.audit.logfile.events.include", "authentication_success") .build(); auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext); - auditTrail.authenticationSuccess(requestId, realm, user, "_action", request); - final MapBuilder checkedFields = new MapBuilder<>(commonFields); - final MapBuilder checkedArrayFields = new MapBuilder<>(); + auditTrail.authenticationSuccess(requestId, authentication, "_action", request); checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "authentication_success") .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") - .put(LoggingAuditTrail.REALM_FIELD_NAME, realm) .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName()) .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); - if (user.isRunAs()) { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "running as"); - checkedFields.put(LoggingAuditTrail.PRINCIPAL_RUN_BY_FIELD_NAME, "_username"); - } else { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, "_username"); - } + authentication(authentication, checkedFields); + restOrTransportOrigin(request, threadContext, checkedFields); + indicesRequest(request, checkedFields, checkedArrayFields); + opaqueId(threadContext, checkedFields); + forwardedFor(threadContext, checkedFields); + assertMsg(logger, checkedFields.immutableMap(), checkedArrayFields.immutableMap()); + + CapturingLogger.output(logger.getName(), Level.INFO).clear(); + + // audit for authn with API Key + authentication = createApiKeyAuthentication(apiKeyService, authentication); + checkedFields = new MapBuilder<>(commonFields); + checkedArrayFields = new MapBuilder<>(); + auditTrail.authenticationSuccess(requestId, authentication, "_action", request); + checkedFields.put(LoggingAuditTrail.EVENT_TYPE_FIELD_NAME, LoggingAuditTrail.TRANSPORT_ORIGIN_FIELD_VALUE) + .put(LoggingAuditTrail.EVENT_ACTION_FIELD_NAME, "authentication_success") + .put(LoggingAuditTrail.ACTION_FIELD_NAME, "_action") + .put(LoggingAuditTrail.REQUEST_NAME_FIELD_NAME, request.getClass().getSimpleName()) + .put(LoggingAuditTrail.REQUEST_ID_FIELD_NAME, requestId); + authentication(authentication, checkedFields); restOrTransportOrigin(request, threadContext, checkedFields); indicesRequest(request, checkedFields, checkedArrayFields); opaqueId(threadContext, checkedFields); @@ -1117,25 +1225,32 @@ public void testRequestsWithoutIndices() throws Exception { auditTrail.authenticationFailed("_req_id", realm, new MockToken(), "_action", request); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.accessGranted("_req_id", createAuthentication(), "_action", request, authorizationInfo); + auditTrail.accessGranted("_req_id", randomBoolean() ? createAuthentication() : createApiKeyAuthentication(apiKeyService, + createAuthentication()), "_action", request, authorizationInfo); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.accessDenied("_req_id", createAuthentication(), "_action", request, authorizationInfo); + auditTrail.accessDenied("_req_id", randomBoolean() ? createAuthentication() : createApiKeyAuthentication(apiKeyService, + createAuthentication()), "_action", request, authorizationInfo); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); auditTrail.tamperedRequest("_req_id", "_action", request); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.tamperedRequest("_req_id", user, "_action", request); + auditTrail.tamperedRequest("_req_id", randomBoolean() ? createAuthentication() : createApiKeyAuthentication(apiKeyService, + createAuthentication()), "_action", request); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.runAsGranted("_req_id", createAuthentication(), "_action", request, authorizationInfo); + auditTrail.runAsGranted("_req_id", randomBoolean() ? createAuthentication() : createApiKeyAuthentication(apiKeyService, + createAuthentication()), "_action", request, authorizationInfo); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.runAsDenied("_req_id", createAuthentication(), "_action", request, authorizationInfo); + auditTrail.runAsDenied("_req_id", randomBoolean() ? createAuthentication() : createApiKeyAuthentication(apiKeyService, + createAuthentication()), "_action", request, authorizationInfo); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); - auditTrail.authenticationSuccess("_req_id", realm, user, "_action", request); + auditTrail.authenticationSuccess("_req_id", randomBoolean() ? createAuthentication() : + createApiKeyAuthentication(apiKeyService, createAuthentication()), + "_action", request); assertThat(output.size(), is(logEntriesCount++)); assertThat(output.get(logEntriesCount - 2), not(containsString("indices="))); } @@ -1232,17 +1347,21 @@ protected static InetAddress forge(String hostname, String address) throws IOExc return InetAddress.getByAddress(hostname, bytes); } - private static Authentication createAuthentication() { + private Authentication createAuthentication() { final RealmRef lookedUpBy; + final RealmRef authBy; final User user; if (randomBoolean()) { - user = new User("running_as", new String[] { "r2" }, new User("_username", new String[] { "r1" })); - lookedUpBy = new RealmRef("lookRealm", "up", "by"); + user = new User(randomAlphaOfLength(4), new String[] { "r1" }, new User("authenticated_username", new String[] { "r2" })); + lookedUpBy = new RealmRef(randomAlphaOfLength(4), "lookup", "by"); + authBy = new RealmRef("authRealm", "auth", "foo"); } else { - user = new User("_username", new String[] { "r1" }); + user = new User(randomAlphaOfLength(4), new String[] { "r1" }); lookedUpBy = null; + authBy = new RealmRef(randomAlphaOfLength(4), "auth", "by"); } - return new Authentication(user, new RealmRef("authRealm", "test", "foo"), lookedUpBy); + return new Authentication(user, authBy, lookedUpBy, Version.CURRENT, randomFrom(AuthenticationType.REALM, + AuthenticationType.TOKEN, AuthenticationType.INTERNAL, AuthenticationType.ANONYMOUS), Collections.emptyMap()); } private ClusterSettings mockClusterSettings() { @@ -1330,14 +1449,25 @@ private static void restOrTransportOrigin(TransportRequest request, ThreadContex } } - private static void subject(Authentication authentication, MapBuilder checkedFields) { + private static void authentication(Authentication authentication, MapBuilder checkedFields) { checkedFields.put(LoggingAuditTrail.PRINCIPAL_FIELD_NAME, authentication.getUser().principal()); - if (authentication.getUser().isRunAs()) { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, authentication.getLookedUpBy().getName()) - .put(LoggingAuditTrail.PRINCIPAL_RUN_BY_FIELD_NAME, authentication.getUser().authenticatedUser().principal()) - .put(LoggingAuditTrail.PRINCIPAL_RUN_BY_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + checkedFields.put(LoggingAuditTrail.AUTHENTICATION_TYPE_FIELD_NAME, authentication.getAuthenticationType().toString()); + if (Authentication.AuthenticationType.API_KEY == authentication.getAuthenticationType()) { + assert false == authentication.getUser().isRunAs(); + checkedFields.put(LoggingAuditTrail.API_KEY_ID_FIELD_NAME, + (String) authentication.getMetadata().get(ApiKeyService.API_KEY_ID_KEY)) + .put(LoggingAuditTrail.API_KEY_NAME_FIELD_NAME, + (String) authentication.getMetadata().get(ApiKeyService.API_KEY_NAME_KEY)) + .put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, + (String) authentication.getMetadata().get(ApiKeyService.API_KEY_CREATOR_REALM_NAME)); } else { - checkedFields.put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + if (authentication.getUser().isRunAs()) { + checkedFields.put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, authentication.getLookedUpBy().getName()) + .put(LoggingAuditTrail.PRINCIPAL_RUN_BY_FIELD_NAME, authentication.getUser().authenticatedUser().principal()) + .put(LoggingAuditTrail.PRINCIPAL_RUN_BY_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + } else { + checkedFields.put(LoggingAuditTrail.PRINCIPAL_REALM_FIELD_NAME, authentication.getAuthenticatedBy().getName()); + } } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index 23357d7f8b48c..d758c16955bf0 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -182,7 +182,13 @@ public void testAuthenticateWithApiKey() throws Exception { final String id = randomAlphaOfLength(12); final String key = randomAlphaOfLength(16); - mockKeyDocument(service, id, key, new User("hulk", "superuser")); + final User user; + if (randomBoolean()) { + user = new User("hulk", new String[] { "superuser" }, new User("authenticated_user", new String[] { "other" })); + } else { + user = new User("hulk", new String[] { "superuser" }); + } + mockKeyDocument(service, id, key, user); final AuthenticationResult auth = tryAuthenticate(service, id, key); assertThat(auth.getStatus(), is(AuthenticationResult.Status.SUCCESS)); @@ -201,7 +207,14 @@ public void testAuthenticationIsSkippedIfLicenseDoesNotAllowIt() throws Exceptio final String id = randomAlphaOfLength(12); final String key = randomAlphaOfLength(16); - mockKeyDocument(service, id, key, new User(randomAlphaOfLength(6), randomAlphaOfLength(12))); + final User user; + if (randomBoolean()) { + user = new User(randomAlphaOfLength(6), new String[] { randomAlphaOfLength(12) }, new User("authenticated_user", + new String[] { "other" })); + } else { + user = new User(randomAlphaOfLength(6), new String[] { randomAlphaOfLength(12) }); + } + mockKeyDocument(service, id, key, user); when(licenseState.checkFeature(Feature.SECURITY_API_KEY_SERVICE)).thenReturn(false); final AuthenticationResult auth = tryAuthenticate(service, id, key); @@ -232,7 +245,13 @@ public void testAuthenticationFailureWithInvalidCredentials() throws Exception { final String realKey = randomAlphaOfLength(16); final String wrongKey = "#" + realKey.substring(1); - mockKeyDocument(service, id, realKey, new User("hulk", "superuser")); + final User user; + if (randomBoolean()) { + user = new User("hulk", new String[] { "superuser" }, new User("authenticated_user", new String[] { "other" })); + } else { + user = new User("hulk", new String[] { "superuser" }); + } + mockKeyDocument(service, id, realKey, user); final AuthenticationResult auth = tryAuthenticate(service, id, wrongKey); assertThat(auth.getStatus(), is(AuthenticationResult.Status.CONTINUE)); @@ -265,7 +284,13 @@ public void testMixingValidAndInvalidCredentials() throws Exception { final String id = randomAlphaOfLength(12); final String realKey = randomAlphaOfLength(16); - mockKeyDocument(service, id, realKey, new User("hulk", "superuser")); + final User user; + if (randomBoolean()) { + user = new User("hulk", new String[] { "superuser" }, new User("authenticated_user", new String[] { "other" })); + } else { + user = new User("hulk", new String[] { "superuser" }); + } + mockKeyDocument(service, id, realKey, user); for (int i = 0; i < 3; i++) { final String wrongKey = "=" + randomAlphaOfLength(14) + "@"; @@ -287,8 +312,17 @@ private void mockKeyDocument(ApiKeyService service, String id, String key, User private void mockKeyDocument(ApiKeyService service, String id, String key, User user, boolean invalidated, Duration expiry) throws IOException { - final Authentication authentication = new Authentication(user, new RealmRef("realm1", "native", - "node01"), null, Version.CURRENT); + final Authentication authentication; + if (user.isRunAs()) { + authentication = new Authentication(user, new RealmRef("authRealm", "test", "foo"), + new RealmRef("realm1", "native", "node01"), Version.CURRENT, + randomFrom(AuthenticationType.REALM, AuthenticationType.TOKEN, AuthenticationType.INTERNAL, + AuthenticationType.ANONYMOUS), Collections.emptyMap()); + } else { + authentication = new Authentication(user, new RealmRef("realm1", "native", "node01"), null, + Version.CURRENT, randomFrom(AuthenticationType.REALM, AuthenticationType.TOKEN, AuthenticationType.INTERNAL, + AuthenticationType.ANONYMOUS), Collections.emptyMap()); + } XContentBuilder docSource = service.newDocument(new SecureString(key.toCharArray()), "test", authentication, Collections.singleton(SUPERUSER_ROLE_DESCRIPTOR), Instant.now(), Instant.now().plus(expiry), null, Version.CURRENT); @@ -736,6 +770,13 @@ public static Authentication createApiKeyAuthentication(ApiKeyService apiKeyServ Clock.systemUTC(), authenticationResultFuture); return apiKeyService.createApiKeyAuthentication(authenticationResultFuture.get(), "node01"); } + + public static Authentication createApiKeyAuthentication(ApiKeyService apiKeyService, + Authentication authentication) throws Exception { + return createApiKeyAuthentication(apiKeyService, authentication, + Collections.singleton(new RoleDescriptor("user_role_" + randomAlphaOfLength(4), new String[]{"manage"}, null, null)), + null); + } } private ApiKeyService createApiKeyService(Settings baseSettings) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index 7c95359f2cfe8..ab257d3564bf0 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -337,6 +337,7 @@ public void testAuthenticateSmartRealmOrdering() { assertThat(result.getAuthenticatedBy().getName(), is(SECOND_REALM_NAME)); assertThat(result.getAuthenticatedBy().getType(), is(SECOND_REALM_TYPE)); assertThreadContextContainsAuthentication(result); + verify(auditTrail).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); assertTrue(completed.get()); @@ -353,13 +354,13 @@ public void testAuthenticateSmartRealmOrdering() { assertThat(result.getAuthenticatedBy().getName(), is(SECOND_REALM_NAME)); assertThat(result.getAuthenticatedBy().getType(), is(SECOND_REALM_TYPE)); assertThreadContextContainsAuthentication(result); + verify(auditTrail, times(2)).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); verify(auditTrail).authenticationFailed(reqId, firstRealm.name(), token, "_action", transportRequest); - verify(auditTrail, times(2)).authenticationSuccess(reqId, secondRealm.name(), user, "_action", transportRequest); verify(firstRealm, times(2)).name(); // used above one time - verify(secondRealm, times(3)).name(); // used above one time + verify(secondRealm, times(2)).name(); verify(secondRealm, times(2)).type(); // used to create realm ref verify(firstRealm, times(2)).token(threadContext); verify(secondRealm, times(2)).token(threadContext); @@ -385,11 +386,11 @@ public void testAuthenticateSmartRealmOrdering() { assertThat(result.getAuthenticatedBy().getName(), is(FIRST_REALM_NAME)); assertThat(result.getAuthenticatedBy().getType(), is(FIRST_REALM_TYPE)); assertThreadContextContainsAuthentication(result); + verify(auditTrail).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); - verify(auditTrail, times(1)).authenticationFailed(reqId, SECOND_REALM_NAME, token, "_action", transportRequest); - verify(auditTrail, times(1)).authenticationSuccess(reqId, FIRST_REALM_NAME, user, "_action", transportRequest); + verify(auditTrail).authenticationFailed(reqId, SECOND_REALM_NAME, token, "_action", transportRequest); verify(secondRealm, times(3)).authenticate(eq(token), any(ActionListener.class)); // 2 from above + 1 more verify(firstRealm, times(2)).authenticate(eq(token), any(ActionListener.class)); // 1 from above + 1 more } @@ -450,8 +451,9 @@ public void testAuthenticateSmartRealmOrderingDisabled() { assertThat(result, notNullValue()); assertThat(result.getUser(), is(user)); assertThat(result.getLookedUpBy(), is(nullValue())); - assertThat(result.getAuthenticatedBy(), is(notNullValue())); // TODO implement equals + assertThat(result.getAuthenticatedBy().getName(), is(SECOND_REALM_NAME)); // TODO implement equals assertThreadContextContainsAuthentication(result); + verify(auditTrail).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); assertTrue(completed.get()); @@ -461,14 +463,14 @@ public void testAuthenticateSmartRealmOrderingDisabled() { assertThat(result, notNullValue()); assertThat(result.getUser(), is(user)); assertThat(result.getLookedUpBy(), is(nullValue())); - assertThat(result.getAuthenticatedBy(), is(notNullValue())); // TODO implement equals + assertThat(result.getAuthenticatedBy().getName(), is(SECOND_REALM_NAME)); // TODO implement equals assertThreadContextContainsAuthentication(result); + verify(auditTrail, times(2)).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); verify(auditTrail, times(2)).authenticationFailed(reqId, firstRealm.name(), token, "_action", transportRequest); - verify(auditTrail, times(2)).authenticationSuccess(reqId, secondRealm.name(), user, "_action", transportRequest); verify(firstRealm, times(3)).name(); // used above one time - verify(secondRealm, times(3)).name(); // used above one time + verify(secondRealm, times(2)).name(); verify(secondRealm, times(2)).type(); // used to create realm ref verify(firstRealm, times(2)).token(threadContext); verify(secondRealm, times(2)).token(threadContext); @@ -492,10 +494,12 @@ public void testAuthenticateFirstNotSupportingSecondSucceeds() throws Exception assertThat(result, notNullValue()); assertThat(result.getUser(), is(user)); assertThat(result.getAuthenticationType(), is(AuthenticationType.REALM)); + assertThat(result.getAuthenticatedBy().getName(), is(secondRealm.name())); // TODO implement equals + assertThat(result.getAuthenticationType(), is(AuthenticationType.REALM)); assertThreadContextContainsAuthentication(result); + verify(auditTrail).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); - verify(auditTrail).authenticationSuccess(reqId, secondRealm.name(), user, "_action", transportRequest); verifyNoMoreInteractions(auditTrail); verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class)); assertTrue(completed.get()); @@ -642,12 +646,13 @@ public void testAuthenticateTransportSuccess() throws Exception { authenticate.accept(ActionListener.wrap(result -> { assertThat(result, notNullValue()); assertThat(result.getUser(), sameInstance(user)); - assertThreadContextContainsAuthentication(result); assertThat(result.getAuthenticationType(), is(AuthenticationType.REALM)); + assertThat(result.getAuthenticatedBy().getName(), is(firstRealm.name())); // TODO implement equals + assertThreadContextContainsAuthentication(result); + verify(auditTrail).authenticationSuccess(reqId, result, "_action", transportRequest); setCompletedToTrue(completed); }, this::logAndFail)); - verify(auditTrail).authenticationSuccess(reqId, firstRealm.name(), user, "_action", transportRequest); verifyNoMoreInteractions(auditTrail); assertTrue(completed.get()); } @@ -663,11 +668,12 @@ public void testAuthenticateRestSuccess() throws Exception { assertThat(authentication, notNullValue()); assertThat(authentication.getUser(), sameInstance(user1)); assertThat(authentication.getAuthenticationType(), is(AuthenticationType.REALM)); + assertThat(authentication.getAuthenticatedBy().getName(), is(firstRealm.name())); // TODO implement equals assertThreadContextContainsAuthentication(authentication); + String reqId = expectAuditRequestId(); + verify(auditTrail).authenticationSuccess(reqId, authentication, restRequest); setCompletedToTrue(completed); }, this::logAndFail)); - String reqId = expectAuditRequestId(); - verify(auditTrail).authenticationSuccess(reqId, firstRealm.name(), user1, restRequest); verifyNoMoreInteractions(auditTrail); assertTrue(completed.get()); } @@ -841,7 +847,7 @@ public void testAnonymousUserRest() throws Exception { assertThat(result.getAuthenticationType(), is(AuthenticationType.ANONYMOUS)); assertThreadContextContainsAuthentication(result); String reqId = expectAuditRequestId(); - verify(auditTrail).authenticationSuccess(reqId, "__anonymous", new AnonymousUser(settings), request); + verify(auditTrail).authenticationSuccess(reqId, result, request); verifyNoMoreInteractions(auditTrail); } @@ -1291,12 +1297,13 @@ public void testAuthenticateWithToken() throws Exception { assertThat(result.getUser(), is(user)); assertThat(result.getLookedUpBy(), is(nullValue())); assertThat(result.getAuthenticatedBy(), is(notNullValue())); + assertThat(result.getAuthenticatedBy().getName(), is("realm")); // TODO implement equals assertThat(result.getAuthenticationType(), is(AuthenticationType.TOKEN)); setCompletedToTrue(completed); + verify(auditTrail).authenticationSuccess(anyString(), eq(result), eq("_action"), same(transportRequest)); }, this::logAndFail)); } assertTrue(completed.get()); - verify(auditTrail).authenticationSuccess(anyString(), eq("realm"), eq(user), eq("_action"), same(transportRequest)); verifyNoMoreInteractions(auditTrail); } @@ -1347,7 +1354,7 @@ public void testInvalidToken() throws Exception { latch.await(); if (success.get()) { final String realmName = firstRealm.name(); - verify(auditTrail).authenticationSuccess(anyString(), eq(realmName), eq(user), eq("_action"), same(transportRequest)); + verify(auditTrail).authenticationSuccess(anyString(), eq(expected), eq("_action"), same(transportRequest)); } verifyNoMoreInteractions(auditTrail); }