diff --git a/server/src/main/java/org/elasticsearch/node/Node.java b/server/src/main/java/org/elasticsearch/node/Node.java index d3f75d38d2cae..2ed7202bc8611 100644 --- a/server/src/main/java/org/elasticsearch/node/Node.java +++ b/server/src/main/java/org/elasticsearch/node/Node.java @@ -195,6 +195,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -753,7 +754,13 @@ protected Node( final IndexingPressure indexingLimits = new IndexingPressure(settings); final TaskTracer taskTracer = transportService.getTaskManager().getTaskTracer(); - pluginComponents.stream().map(c -> c instanceof Tracer ? (Tracer) c : null).forEach(taskTracer::addTracer); + final List tracers = pluginComponents.stream() + .map(c -> c instanceof Tracer ? (Tracer) c : null) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + tracers.forEach(taskTracer::addTracer); + + pluginsService.filterPlugins(Plugin.class).forEach(plugin -> plugin.onTracers(tracers)); final RecoverySettings recoverySettings = new RecoverySettings(settings, settingsModule.getClusterSettings()); RepositoriesModule repositoriesModule = new RepositoriesModule( diff --git a/server/src/main/java/org/elasticsearch/plugins/Plugin.java b/server/src/main/java/org/elasticsearch/plugins/Plugin.java index 9d784c3ba49c8..26d69eeeb1293 100644 --- a/server/src/main/java/org/elasticsearch/plugins/Plugin.java +++ b/server/src/main/java/org/elasticsearch/plugins/Plugin.java @@ -27,6 +27,7 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.tracing.Tracer; import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xcontent.NamedXContentRegistry; import org.elasticsearch.xcontent.XContentParser; @@ -204,4 +205,9 @@ public void close() throws IOException { public Collection getAdditionalIndexSettingProviders() { return Collections.emptyList(); } + + /** + * Called with a list of Tracers so that each plugin can have a chance to work with them. + */ + public void onTracers(List tracers) {} } diff --git a/server/src/main/java/org/elasticsearch/tracing/Tracer.java b/server/src/main/java/org/elasticsearch/tracing/Tracer.java index dd4454b8e6b62..bba75825681a5 100644 --- a/server/src/main/java/org/elasticsearch/tracing/Tracer.java +++ b/server/src/main/java/org/elasticsearch/tracing/Tracer.java @@ -8,6 +8,8 @@ package org.elasticsearch.tracing; +import java.util.Map; + /** * Represents a distributed tracing system that keeps track of the start and end of various activities in the cluster. */ @@ -22,4 +24,9 @@ public interface Tracer { * Called when the {@link Traceable} activity ends. */ void onTraceStopped(Traceable traceable); + + /** + * Retrieve context related headers for the span of the given id. + */ + Map getSpanHeadersById(String id); } diff --git a/x-pack/plugin/apm-integration/build.gradle b/x-pack/plugin/apm-integration/build.gradle index 2616d09aa15b4..2fa3c336e2334 100644 --- a/x-pack/plugin/apm-integration/build.gradle +++ b/x-pack/plugin/apm-integration/build.gradle @@ -56,6 +56,9 @@ dependencies { compileOnly project(path: xpackModule('core')) internalClusterTestImplementation(testArtifact(project(xpackModule('core')))) + internalClusterTestImplementation(testArtifact(project(xpackModule('security')))) { + exclude group: 'com.google.guava', module: 'guava' + } } // no unit-test for now diff --git a/x-pack/plugin/apm-integration/src/internalClusterTest/java/org/elasticsearch/xpack/apm/ApmIT.java b/x-pack/plugin/apm-integration/src/internalClusterTest/java/org/elasticsearch/xpack/apm/ApmIT.java index be1b1cf5b09ac..b54a54a2781d2 100644 --- a/x-pack/plugin/apm-integration/src/internalClusterTest/java/org/elasticsearch/xpack/apm/ApmIT.java +++ b/x-pack/plugin/apm-integration/src/internalClusterTest/java/org/elasticsearch/xpack/apm/ApmIT.java @@ -15,21 +15,25 @@ import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.search.SearchTransportService; -import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.common.settings.MockSecureSettings; +import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.CollectionUtils; -import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskTracer; -import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; +import org.elasticsearch.test.SecuritySettingsSourceField; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.junit.After; import java.util.Collection; @@ -44,7 +48,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.notNullValue; -public class ApmIT extends ESIntegTestCase { +public class ApmIT extends SecurityIntegTestCase { @Override protected Collection> nodePlugins() { @@ -53,15 +57,22 @@ protected Collection> nodePlugins() { @Override protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { - final MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString(APMTracer.APM_ENDPOINT_SETTING.getKey(), System.getProperty("tests.apm.endpoint", "")); - secureSettings.setString(APMTracer.APM_TOKEN_SETTING.getKey(), System.getProperty("tests.apm.token", "")); - - return Settings.builder() - .put(super.nodeSettings(nodeOrdinal, otherSettings)) - .put(APMTracer.APM_ENABLED_SETTING.getKey(), true) - .setSecureSettings(secureSettings) - .build(); + Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal, otherSettings)); + ((MockSecureSettings) builder.getSecureSettings()).setString( + APMTracer.APM_ENDPOINT_SETTING.getKey(), + System.getProperty("tests.apm.endpoint", "") + ); + ((MockSecureSettings) builder.getSecureSettings()).setString( + APMTracer.APM_TOKEN_SETTING.getKey(), + System.getProperty("tests.apm.token", "") + ); + builder.put(APMTracer.APM_ENABLED_SETTING.getKey(), true).put("xpack.security.authz.tracing", true); + return builder.build(); + } + + @Override + protected boolean addMockHttpTransport() { + return false; } @After @@ -166,12 +177,23 @@ public void testSearch() throws Exception { final APMTracer.CapturingSpanExporter spanExporter = APMTracer.CAPTURING_SPAN_EXPORTER; spanExporter.clear(); - client().prepareSearch() - .setQuery(new RangeQueryBuilder("@timestamp").gt("2021-11-01")) - .setSearchType(SearchType.QUERY_THEN_FETCH) - .setPreFilterShardSize(1) - .execute() - .actionGet(10, TimeUnit.SECONDS); + final Request searchRequest = new Request("GET", "_search"); + searchRequest.addParameter("search_type", "query_then_fetch"); + searchRequest.addParameter("pre_filter_shard_size", "1"); + searchRequest.setJsonEntity("{\"query\":{\"range\":{\"@timestamp\":{\"gt\":\"2021-11-01\"}}}}"); + searchRequest.setOptions( + searchRequest.getOptions() + .toBuilder() + .addHeader( + "Authorization", + UsernamePasswordToken.basicAuthHeaderValue( + SecuritySettingsSource.TEST_USER_NAME, + new SecureString(SecuritySettingsSourceField.TEST_PASSWORD.toCharArray()) + ) + ) + ); + + final Response searchResponse = getRestClient().performRequest(searchRequest); assertTrue(spanExporter.findSpanByName(SearchAction.NAME).findAny().isPresent()); assertTrue(spanExporter.findSpanByName(SearchTransportService.QUERY_CAN_MATCH_NODE_NAME).findAny().isPresent()); diff --git a/x-pack/plugin/apm-integration/src/main/java/org/elasticsearch/xpack/apm/APMTracer.java b/x-pack/plugin/apm-integration/src/main/java/org/elasticsearch/xpack/apm/APMTracer.java index 56de34778ae86..7aa777fc5a504 100644 --- a/x-pack/plugin/apm-integration/src/main/java/org/elasticsearch/xpack/apm/APMTracer.java +++ b/x-pack/plugin/apm-integration/src/main/java/org/elasticsearch/xpack/apm/APMTracer.java @@ -214,6 +214,10 @@ public void onTraceStarted(Traceable traceable) { ); } } + final String xOpaqueId = threadPool.getThreadContext().getHeader(Task.X_OPAQUE_ID); + if (xOpaqueId != null) { + spanBuilder.setAttribute("es.x-opaque-id", xOpaqueId); + } return spanBuilder.startSpan(); }); } @@ -239,6 +243,7 @@ private Context getParentSpanContext(OpenTelemetry openTelemetry) { return null; } + @Override public Map getSpanHeadersById(String id) { var services = this.services; var span = spans.get(id); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/AuthorizationTracer.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/AuthorizationTracer.java new file mode 100644 index 0000000000000..b1fffbc0986c2 --- /dev/null +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/AuthorizationTracer.java @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.security; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.ParameterizedMessage; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.tracing.Traceable; +import org.elasticsearch.tracing.Tracer; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class AuthorizationTracer { + + private static final Logger logger = LogManager.getLogger(AuthorizationTracer.class); + + private final ThreadContext threadContext; + private final List tracers = new CopyOnWriteArrayList<>(); + + public AuthorizationTracer(ThreadContext threadContext) { + this.threadContext = threadContext; + } + + public void addTracer(Tracer tracer) { + if (tracer != null) { + tracers.add(tracer); + } + } + + public Runnable startTracing(Traceable traceable) { + for (Tracer tracer : tracers) { + try { + tracer.onTraceStarted(traceable); + } catch (Exception e) { + assert false : e; + logger.warn( + new ParameterizedMessage( + "authorization tracing listener [{}] failed on starting tracing of [{}][{}]", + tracer, + traceable.getSpanId(), + traceable.getSpanName() + ), + e + ); + } + } + return () -> { + for (Tracer tracer : tracers) { + try { + tracer.onTraceStopped(traceable); + } catch (Exception e) { + assert false : e; + logger.warn( + new ParameterizedMessage( + "authorization tracing listener [{}] failed on stopping tracing of [{}][{}]", + tracer, + traceable.getSpanId(), + traceable.getSpanName() + ), + e + ); + } + } + }; + } +} diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index f125fd186592e..9f18b81b870ce 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -75,6 +75,7 @@ import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.tracing.Tracer; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportInterceptor; import org.elasticsearch.transport.TransportRequest; @@ -470,6 +471,7 @@ public class Security extends Plugin private final List securityExtensions = new ArrayList<>(); private final SetOnce transportReference = new SetOnce<>(); private final SetOnce scriptServiceReference = new SetOnce<>(); + private final SetOnce authorizationTracerReference = new SetOnce<>(); public Security(Settings settings, final Path configPath) { this(settings, configPath, Collections.emptyList()); @@ -810,6 +812,7 @@ Collection createComponents( } requestInterceptors = Collections.unmodifiableSet(requestInterceptors); + authorizationTracerReference.set(new AuthorizationTracer(threadContext.get())); final AuthorizationService authzService = new AuthorizationService( settings, allRolesStore, @@ -822,7 +825,8 @@ Collection createComponents( requestInterceptors, getLicenseState(), expressionResolver, - operatorPrivilegesService + operatorPrivilegesService, + authorizationTracerReference.get() ); components.add(nativeRolesStore); // used by roles actions @@ -1602,6 +1606,15 @@ public void loadExtensions(ExtensionLoader loader) { securityExtensions.addAll(loader.loadExtensions(SecurityExtension.class)); } + @Override + public void onTracers(List tracers) { + if (authorizationTracerReference.get() == null) { + // security is disabled + return; + } + tracers.forEach(t -> authorizationTracerReference.get().addTracer(t)); + } + private synchronized NioGroupFactory getNioGroupFactory(Settings settings) { if (nioGroupFactory.get() != null) { assert nioGroupFactory.get().getSettings().equals(settings) : "Different settings than originally provided"; 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 bb271f1098da7..41a29162da9f1 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 @@ -39,6 +39,7 @@ import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.tracing.Traceable; import org.elasticsearch.transport.TransportActionProxy; import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.xpack.core.MigrateToDataStreamAction; @@ -71,6 +72,7 @@ import org.elasticsearch.xpack.core.security.user.AnonymousUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; +import org.elasticsearch.xpack.security.AuthorizationTracer; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; @@ -111,6 +113,7 @@ public class AuthorizationService { true, Property.NodeScope ); + public static final Setting TRACE_AUTHORIZATION = Setting.boolSetting(setting("authz.tracing"), true, Property.NodeScope); private static final AuthorizationInfo SYSTEM_AUTHZ_INFO = () -> Collections.singletonMap( PRINCIPAL_ROLES_FIELD_NAME, new String[] { SystemUser.ROLE_NAME } @@ -132,6 +135,8 @@ public class AuthorizationService { private final Set requestInterceptors; private final XPackLicenseState licenseState; private final OperatorPrivilegesService operatorPrivilegesService; + private final AuthorizationTracer authorizationTracer; + private final boolean tracingEnabled; private final boolean isAnonymousEnabled; private final boolean anonymousAuthzExceptionEnabled; @@ -147,7 +152,8 @@ public AuthorizationService( Set requestInterceptors, XPackLicenseState licenseState, IndexNameExpressionResolver resolver, - OperatorPrivilegesService operatorPrivilegesService + OperatorPrivilegesService operatorPrivilegesService, + AuthorizationTracer authorizationTracer ) { this.clusterService = clusterService; this.auditTrailService = auditTrailService; @@ -163,6 +169,8 @@ public AuthorizationService( this.settings = settings; this.licenseState = licenseState; this.operatorPrivilegesService = operatorPrivilegesService; + this.authorizationTracer = authorizationTracer; + this.tracingEnabled = TRACE_AUTHORIZATION.get(settings); } public void checkPrivileges( @@ -211,6 +219,8 @@ public void authorize( final AuthorizationContext enclosingContext = extractAuthorizationContext(threadContext, action); + final Runnable tracer = maybeStartTracing(enclosingContext, authentication, action, originalRequest); + /* authorization fills in certain transient headers, which must be observed in the listener (action handler execution) * as well, but which must not bleed across different action context (eg parent-child action contexts). *

@@ -256,6 +266,8 @@ public void authorize( }, listener::onFailure), threadContext); engine.resolveAuthorizationInfo(requestInfo, authzInfoListener); } + } finally { + tracer.run(); } } @@ -309,6 +321,48 @@ private static ElasticsearchSecurityException internalError(String message) { return new ElasticsearchSecurityException(message); } + private Runnable maybeStartTracing( + AuthorizationContext enclosingContext, + Authentication authentication, + String action, + TransportRequest originalRequest + ) { + // Not tracing system actions + if (false == tracingEnabled || SystemUser.is(authentication.getUser())) { + return () -> {}; + } else { + return authorizationTracer.startTracing(new Traceable() { + @Override + public String getSpanId() { + return "authorize_" + System.identityHashCode(originalRequest); + } + + @Override + public String getSpanName() { + return "authorize(" + action + ")"; + } + + @Override + public Map getAttributes() { + final HashMap attributes = new HashMap<>( + Map.of( + "es.principal", + authentication.getUser().principal(), + "es.authentication.realm.name", + authentication.getAuthenticatedBy().getName(), + "es.node.name", + clusterService.getNodeName() + ) + ); + if (enclosingContext != null) { + attributes.put("originating_action", enclosingContext.getAction()); + } + return Map.copyOf(attributes); + } + }); + } + } + private void checkOperatorPrivileges(Authentication authentication, String action, TransportRequest originalRequest) throws ElasticsearchSecurityException { // Check operator privileges @@ -1074,5 +1128,6 @@ public void done(Collection indices) { public static void addSettings(List> settings) { settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING); + settings.add(TRACE_AUTHORIZATION); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java index 22e53ecfd2511..214a7f0ab5aaa 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java @@ -13,6 +13,7 @@ import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.Maps; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -24,9 +25,11 @@ import org.elasticsearch.rest.RestRequest.Method; import org.elasticsearch.rest.RestRequestFilter; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.tasks.Task; import org.elasticsearch.xcontent.MediaType; import org.elasticsearch.xcontent.MediaTypeRegistry; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.xpack.security.authc.support.SecondaryAuthenticator; import org.elasticsearch.xpack.security.transport.SSLEngineUtils; @@ -111,6 +114,12 @@ public void handleRequest(RestRequest request, RestChannel channel, NodeClient c } RemoteHostHeader.process(request, threadContext); try { + // Populate x-opaque-id if not already exists to chain all related actions together + if (authentication != null && false == SystemUser.is(authentication.getUser())) { + if (threadContext.getHeader(Task.X_OPAQUE_ID) == null) { + threadContext.putHeader(Task.X_OPAQUE_ID, UUIDs.base64UUID()); + } + } restHandler.handleRequest(request, channel, client); } catch (Exception e) { handleException(ActionType.RequestHandling, request, channel, e); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java index 9946f5d2a2c49..d76643c50688b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java @@ -19,6 +19,7 @@ import org.elasticsearch.protocol.xpack.XPackInfoResponse; import org.elasticsearch.protocol.xpack.XPackUsageRequest; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.tracing.Tracer; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; import org.elasticsearch.xpack.core.action.TransportXPackInfoAction; @@ -112,4 +113,9 @@ protected Class protected Class> getInfoAction() { return SecurityTransportXPackInfoAction.class; } + + @Override + public void onTracers(List tracers) { + plugins.forEach(plugin -> plugin.onTracers(tracers)); + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index 7ebb5dfb7491e..d51923951e960 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -155,6 +155,7 @@ import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.security.user.XPackSecurityUser; import org.elasticsearch.xpack.core.security.user.XPackUser; +import org.elasticsearch.xpack.security.AuthorizationTracer; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; @@ -287,7 +288,8 @@ public void setup() { Collections.emptySet(), licenseState, TestIndexNameExpressionResolver.newInstance(), - operatorPrivilegesService + operatorPrivilegesService, + new AuthorizationTracer(threadContext) ); } @@ -1561,7 +1563,8 @@ public void testDenialForAnonymousUser() throws IOException { Collections.emptySet(), new XPackLicenseState(() -> 0), TestIndexNameExpressionResolver.newInstance(), - operatorPrivilegesService + operatorPrivilegesService, + new AuthorizationTracer(threadContext) ); RoleDescriptor role = new RoleDescriptor( @@ -1607,7 +1610,8 @@ public void testDenialForAnonymousUserAuthorizationExceptionDisabled() throws IO Collections.emptySet(), new XPackLicenseState(() -> 0), TestIndexNameExpressionResolver.newInstance(), - operatorPrivilegesService + operatorPrivilegesService, + new AuthorizationTracer(threadContext) ); RoleDescriptor role = new RoleDescriptor( @@ -2723,7 +2727,8 @@ public void getUserPrivileges( Collections.emptySet(), licenseState, TestIndexNameExpressionResolver.newInstance(), - operatorPrivilegesService + operatorPrivilegesService, + new AuthorizationTracer(threadContext) ); Authentication authentication; try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {