diff --git a/server/src/main/java/org/elasticsearch/client/internal/ClientAuthHelperService.java b/server/src/main/java/org/elasticsearch/client/internal/ClientAuthHelperService.java new file mode 100644 index 0000000000000..dfa8a6eaf3915 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/client/internal/ClientAuthHelperService.java @@ -0,0 +1,56 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.client.internal; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.ActionType; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.common.util.concurrent.ThreadContext; + +import java.util.Map; + +/** + * This provides helper methods for dealing with the execution of requests made using a {@link Client} such that they + * have the origin as a transient, and listeners have the appropriate context upon invocation. + */ +public interface ClientAuthHelperService { + /** + * This method retrieves the security headers from the given threadContext. + * @param threadContext The ThreadContext from which the security headers are retrieved. + * @param clusterState Used to make sure the headers are written in a way that can be handled by all nodes in the cluster. + */ + Map getPersistableSafeSecurityHeaders(ThreadContext threadContext, ClusterState clusterState); + + /** + * This method executes a client operation asynchronously. It uses auth from the given headers if present, falling back + * to the given origin if there are no auth headers. + * + * @param headers + * Request headers, as retrieved by {@link #getPersistableSafeSecurityHeaders(ThreadContext, ClusterState)} + * @param origin + * The origin to fall back to if there are no security headers + * @param action + * The action to execute + * @param request + * The request object for the action + * @param listener + * The listener to call when the action is complete + */ + void executeWithHeadersAsync( + Map headers, + String origin, + Client client, + ActionType action, + Request request, + ActionListener listener + ); +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java index f79a3fbf124b1..cdd4aa7094171 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java @@ -10,9 +10,13 @@ import org.apache.logging.log4j.Logger; import org.apache.lucene.util.SetOnce; import org.elasticsearch.SpecialPermission; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.ActionType; import org.elasticsearch.action.support.TransportAction; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.client.internal.ClientAuthHelperService; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.Metadata; @@ -31,6 +35,7 @@ import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.ssl.SslConfiguration; import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.core.Booleans; import org.elasticsearch.env.Environment; import org.elasticsearch.features.NodeFeature; @@ -344,6 +349,7 @@ public Collection createComponents(PluginServices services) { components.add(new PluginComponentBinding<>(MutableLicenseService.class, licenseService)); components.add(new PluginComponentBinding<>(LicenseService.class, licenseService)); components.add(getLicenseState()); + components.add(new PluginComponentBinding<>(ClientAuthHelperService.class, getClientAuthHelperService())); return components; } @@ -523,4 +529,25 @@ public void loadExtensions(ExtensionLoader loader) { ); } } + + private ClientAuthHelperService getClientAuthHelperService() { + return new ClientAuthHelperService() { + @Override + public Map getPersistableSafeSecurityHeaders(ThreadContext threadContext, ClusterState clusterState) { + return ClientHelper.getPersistableSafeSecurityHeaders(threadContext, clusterState); + } + + @Override + public void executeWithHeadersAsync( + Map headers, + String origin, + Client client, + ActionType action, + Request request, + ActionListener listener + ) { + ClientHelper.executeWithHeadersAsync(headers, origin, client, action, request, listener); + } + }; + } }