From fc3f266413f6ead33dff62192b6a6107d132243b Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Sun, 23 Apr 2023 01:51:48 -0400 Subject: [PATCH 1/2] Introduce IdentityPlugin with initial interface for extensions use-cases Signed-off-by: Craig Perkins --- .../extensions/ExtensionsManager.java | 6 ++ .../opensearch/identity/IdentityService.java | 59 ++++++++++++++++++ .../opensearch/identity/NamedPrincipal.java | 50 +++++++++++++++ .../org/opensearch/identity/Principals.java | 36 +++++++++++ .../java/org/opensearch/identity/Subject.java | 36 +++++++++++ .../org/opensearch/identity/TokenManager.java | 35 +++++++++++ .../identity/noop/NoopIdentityPlugin.java | 34 +++++++++++ .../opensearch/identity/noop/NoopSubject.java | 61 +++++++++++++++++++ .../opensearch/identity/noop/NoopToken.java | 22 +++++++ .../identity/noop/NoopTokenManager.java | 35 +++++++++++ .../identity/noop/package-info.java | 10 +++ .../org/opensearch/identity/package-info.java | 10 +++ .../opensearch/identity/tokens/AuthToken.java | 28 +++++++++ .../identity/tokens/BearerToken.java | 24 ++++++++ .../identity/tokens/package-info.java | 10 +++ .../main/java/org/opensearch/node/Node.java | 7 +++ .../opensearch/plugins/IdentityPlugin.java | 30 +++++++++ 17 files changed, 493 insertions(+) create mode 100644 server/src/main/java/org/opensearch/identity/IdentityService.java create mode 100644 server/src/main/java/org/opensearch/identity/NamedPrincipal.java create mode 100644 server/src/main/java/org/opensearch/identity/Principals.java create mode 100644 server/src/main/java/org/opensearch/identity/Subject.java create mode 100644 server/src/main/java/org/opensearch/identity/TokenManager.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/NoopSubject.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/NoopToken.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/NoopTokenManager.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/package-info.java create mode 100644 server/src/main/java/org/opensearch/identity/package-info.java create mode 100644 server/src/main/java/org/opensearch/identity/tokens/AuthToken.java create mode 100644 server/src/main/java/org/opensearch/identity/tokens/BearerToken.java create mode 100644 server/src/main/java/org/opensearch/identity/tokens/package-info.java create mode 100644 server/src/main/java/org/opensearch/plugins/IdentityPlugin.java diff --git a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java index 2d432f28bd014..5dc842533152c 100644 --- a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java +++ b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java @@ -56,6 +56,7 @@ import org.opensearch.extensions.rest.RestActionsRequestHandler; import org.opensearch.extensions.settings.CustomSettingsRequestHandler; import org.opensearch.extensions.settings.RegisterCustomSettingsRequest; +import org.opensearch.identity.IdentityService; import org.opensearch.index.IndexModule; import org.opensearch.index.IndexService; import org.opensearch.index.IndicesModuleRequest; @@ -114,6 +115,7 @@ public static enum OpenSearchRequestType { private CustomSettingsRequestHandler customSettingsRequestHandler; private TransportService transportService; private ClusterService clusterService; + private IdentityService identityService; private Settings environmentSettings; private AddSettingsUpdateConsumerRequestHandler addSettingsUpdateConsumerRequestHandler; private NodeClient client; @@ -663,6 +665,10 @@ public ClusterService getClusterService() { return clusterService; } + public void setIdentityService(IdentityService identityService) { + this.identityService = identityService; + } + public static String getRequestExtensionRegisterRestActions() { return REQUEST_EXTENSION_REGISTER_REST_ACTIONS; } diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java new file mode 100644 index 0000000000000..a1395efe27b14 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -0,0 +1,59 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.identity; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.OpenSearchException; +import org.opensearch.identity.noop.NoopIdentityPlugin; +import java.util.List; +import org.opensearch.common.settings.Settings; +import org.opensearch.plugins.IdentityPlugin; +import java.util.stream.Collectors; + +/** + * Identity and access control for OpenSearch. + * + * @opensearch.experimental + * */ +public class IdentityService { + private static final Logger logger = LogManager.getLogger(IdentityService.class); + + private final Settings settings; + private final IdentityPlugin identityPlugin; + + public IdentityService(final Settings settings, final List identityPlugins) { + this.settings = settings; + + if (identityPlugins.size() == 0) { + identityPlugin = new NoopIdentityPlugin(); + } else if (identityPlugins.size() == 1) { + identityPlugin = identityPlugins.get(0); + } else { + throw new OpenSearchException( + "Multiple identity plugins are not supported, found: " + + identityPlugins.stream().map(Object::getClass).map(Class::getName).collect(Collectors.joining(",")) + ); + } + + logger.info("Identity module loaded with " + identityPlugin.getClass().getName()); + logger.info("Current subject " + getSubject()); + } + + /** + * Gets the current subject + */ + public Subject getSubject() { + return identityPlugin.getSubject(); + } + + /** + * Gets the token manager + */ + public TokenManager getTokenManager() { + return identityPlugin.getTokenManager(); + } +} diff --git a/server/src/main/java/org/opensearch/identity/NamedPrincipal.java b/server/src/main/java/org/opensearch/identity/NamedPrincipal.java new file mode 100644 index 0000000000000..bf62daa87d80d --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/NamedPrincipal.java @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.identity; + +import java.security.Principal; +import java.util.Objects; + +/** + * Create a principal from a string + * + * @opensearch.experimental + */ +public class NamedPrincipal implements Principal { + + private final String name; + + /** + * Creates a principal for an identity specified as a string + * @param name A persistent string that represent an identity + */ + public NamedPrincipal(final String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + final Principal that = (Principal) obj; + return Objects.equals(name, that.getName()); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return "StringPrincipal(" + "name=" + name + ")"; + } +} diff --git a/server/src/main/java/org/opensearch/identity/Principals.java b/server/src/main/java/org/opensearch/identity/Principals.java new file mode 100644 index 0000000000000..825c331f32c3f --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/Principals.java @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.identity; + +import java.security.Principal; + +/** + * Available OpenSearch internal principals + * + * @opensearch.experimental + */ +public enum Principals { + + /** + * Represents a principal which has not been authenticated + */ + UNAUTHENTICATED(new NamedPrincipal("Unauthenticated")), + NONE(new NamedPrincipal("None")); + + private final Principal principal; + + Principals(final Principal principal) { + this.principal = principal; + } + + /** + * Returns the underlying principal for this + */ + public Principal getPrincipal() { + return principal; + } + +} diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java new file mode 100644 index 0000000000000..5cfb6f905813a --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.identity; + +import java.security.Principal; + +/** + * An individual, process, or device that causes information to flow among objects or change to the system state. + * + * @opensearch.experimental + */ +public interface Subject { + + /** + * Get the application-wide uniquely identifying principal + * */ + Principal getPrincipal(); + + /** + * Login through an authentication token + * throws UnsupportedAuthenticationMethod + * throws InvalidAuthenticationToken + * throws SubjectNotFound + * throws SubjectDisabled + */ + // TODO Uncomment login and make a richer interface to IdentityPlugin for authc and authz use-cases + // void login(final AuthToken token); + + /** + * Method that returns whether the current subject of the running thread is authenticated + */ + boolean isAuthenticated(); +} diff --git a/server/src/main/java/org/opensearch/identity/TokenManager.java b/server/src/main/java/org/opensearch/identity/TokenManager.java new file mode 100644 index 0000000000000..4cb1e3e3d1cdf --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/TokenManager.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity; + +import org.opensearch.OpenSearchSecurityException; +import org.opensearch.identity.tokens.AuthToken; + +/** + * Interface for a token manager to issue Auth Tokens for a User + * + * @opensearch.experimental + */ +public interface TokenManager { + /** + * Issue an access token on-behalf-of authenticated user for a service to utilize to interact with + * the OpenSearch cluster on-behalf-of the original user + * */ + AuthToken issueAccessTokenOnBehalfOfAuthenticatedUser(String extensionUniqueId) throws OpenSearchSecurityException; + + /** + * Issue a refresh token on-behalf-of authenticated user for a service to refresh access tokens + * */ + AuthToken issueRefreshTokenOnBehalfOfAuthenticatedUser(String extensionUniqueId) throws OpenSearchSecurityException; + + /** + * Issue a service account token for an extension's service account + * */ + AuthToken generateServiceAccountToken(String extensionUniqueId) throws OpenSearchSecurityException; +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java new file mode 100644 index 0000000000000..a50b83ac94a96 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.noop; + +import org.opensearch.identity.TokenManager; +import org.opensearch.plugins.IdentityPlugin; +import org.opensearch.identity.Subject; + +/** + * Implementation of identity plugin that does not enforce authentication or authorization + * + * This class and related classes in this package will not return nulls or fail access checks + * + * @opensearch.internal + */ +public class NoopIdentityPlugin implements IdentityPlugin { + + @Override + public Subject getSubject() { + return new NoopSubject(); + } + + @Override + public TokenManager getTokenManager() { + return new NoopTokenManager(); + } + +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java new file mode 100644 index 0000000000000..211d95d6f354e --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.noop; + +import java.security.Principal; +import java.util.Objects; + +import org.opensearch.identity.Subject; +import org.opensearch.identity.Principals; + +/** + * Implementation of subject that is always authenticated + * + * This class and related classes in this package will not return nulls or fail permissions checks + * + * @opensearch.internal + */ +public class NoopSubject implements Subject { + + @Override + public Principal getPrincipal() { + return Principals.NONE.getPrincipal(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Subject that = (Subject) obj; + return Objects.equals(getPrincipal(), that.getPrincipal()); + } + + @Override + public int hashCode() { + return Objects.hash(getPrincipal()); + } + + @Override + public String toString() { + return "NoopSubject(principal=" + getPrincipal() + ")"; + } + + /** + * Logs the user in + */ + // @Override + // public void login(AuthToken AuthToken) { + // // Do nothing as noop subject is always logged in + // } + + @Override + public boolean isAuthenticated() { + return true; + } +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopToken.java b/server/src/main/java/org/opensearch/identity/noop/NoopToken.java new file mode 100644 index 0000000000000..5803c544b6cc2 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/NoopToken.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.noop; + +import org.opensearch.identity.tokens.AuthToken; + +/** + * Implementation of an AuthToken that gives back an empty token + * + * @opensearch.experimental + */ +public class NoopToken extends AuthToken { + public NoopToken(String tokenValue) { + super(tokenValue); + } +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopTokenManager.java b/server/src/main/java/org/opensearch/identity/noop/NoopTokenManager.java new file mode 100644 index 0000000000000..3c2681ebdf1b3 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/NoopTokenManager.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.noop; + +import org.opensearch.OpenSearchSecurityException; +import org.opensearch.identity.TokenManager; +import org.opensearch.identity.tokens.AuthToken; + +/** + * Implementation of a TokenManager that gives back NoopTokens + * + * @opensearch.experimental + */ +public class NoopTokenManager implements TokenManager { + @Override + public AuthToken issueAccessTokenOnBehalfOfAuthenticatedUser(String extensionUniqueId) { + return new NoopToken(""); + } + + @Override + public AuthToken issueRefreshTokenOnBehalfOfAuthenticatedUser(String extensionUniqueId) { + return new NoopToken(""); + } + + @Override + public AuthToken generateServiceAccountToken(String extensionUniqueId) throws OpenSearchSecurityException { + return new NoopToken(""); + } +} diff --git a/server/src/main/java/org/opensearch/identity/noop/package-info.java b/server/src/main/java/org/opensearch/identity/noop/package-info.java new file mode 100644 index 0000000000000..fcdd70db7f020 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for the noop authentication in OpenSearch */ +package org.opensearch.identity.noop; diff --git a/server/src/main/java/org/opensearch/identity/package-info.java b/server/src/main/java/org/opensearch/identity/package-info.java new file mode 100644 index 0000000000000..8a7bb50704e15 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Core identity and access controls for OpenSearch */ +package org.opensearch.identity; diff --git a/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java b/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java new file mode 100644 index 0000000000000..81f5938d52241 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.tokens; + +/** + * Interface for all token formats to support to authenticate user such as UserName/Password tokens, Access tokens, and more. + * + * @opensearch.experimental + */ +public abstract class AuthToken { + + private final String tokenValue; + + public AuthToken(String tokenValue) { + this.tokenValue = tokenValue; + } + + public String getTokenValue() { + return this.tokenValue; + } + +} diff --git a/server/src/main/java/org/opensearch/identity/tokens/BearerToken.java b/server/src/main/java/org/opensearch/identity/tokens/BearerToken.java new file mode 100644 index 0000000000000..c1652eb5524b4 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/tokens/BearerToken.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.tokens; + +/** + * Class that represents a token used for HTTP Bearer Authentication + * + * Bearer tokens are passed in the HTTP Authorization header + * + * Authorization: Bearer {bearer_token} + * + * @opensearch.experimental + */ +public class BearerToken extends AuthToken { + public BearerToken(String tokenValue) { + super(tokenValue); + } +} diff --git a/server/src/main/java/org/opensearch/identity/tokens/package-info.java b/server/src/main/java/org/opensearch/identity/tokens/package-info.java new file mode 100644 index 0000000000000..b63ea40c61659 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/tokens/package-info.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/** Classes for the authentication tokens in OpenSearch */ +package org.opensearch.identity.tokens; diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index dc4a11cf7102a..8e923e53e2dc0 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -42,6 +42,7 @@ import org.opensearch.common.unit.ByteSizeValue; import org.opensearch.common.util.FeatureFlags; import org.opensearch.cluster.routing.allocation.AwarenessReplicaBalance; +import org.opensearch.identity.IdentityService; import org.opensearch.index.IndexModule; import org.opensearch.index.IndexingPressureService; import org.opensearch.index.store.remote.filecache.FileCache; @@ -54,6 +55,7 @@ import org.opensearch.extensions.NoopExtensionsManager; import org.opensearch.monitor.fs.FsInfo; import org.opensearch.monitor.fs.FsProbe; +import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.SearchPipelinePlugin; import org.opensearch.search.backpressure.SearchBackpressureService; import org.opensearch.search.backpressure.settings.SearchBackpressureSettings; @@ -454,12 +456,16 @@ protected Node( // Ensure to initialize Feature Flags via the settings from opensearch.yml FeatureFlags.initializeFeatureFlags(settings); + final List identityPlugins = pluginsService.filterPlugins(IdentityPlugin.class); + final IdentityService identityService = new IdentityService(settings, identityPlugins); if (FeatureFlags.isEnabled(FeatureFlags.EXTENSIONS)) { this.extensionsManager = new ExtensionsManager(tmpSettings, initialEnvironment.extensionDir()); } else { this.extensionsManager = new NoopExtensionsManager(); } + this.extensionsManager.setIdentityService(identityService); + final Set additionalRoles = pluginsService.filterPlugins(Plugin.class) .stream() .map(Plugin::getRoles) @@ -1124,6 +1130,7 @@ protected Node( b.bind(ShardLimitValidator.class).toInstance(shardLimitValidator); b.bind(FsHealthService.class).toInstance(fsHealthService); b.bind(SystemIndices.class).toInstance(systemIndices); + b.bind(IdentityService.class).toInstance(identityService); }); injector = modules.createInjector(); diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java new file mode 100644 index 0000000000000..83fc526875413 --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.identity.Subject; +import org.opensearch.identity.TokenManager; + +/** + * Plugin that provides identity and access control for OpenSearch + * + * @opensearch.experimental + */ +public interface IdentityPlugin { + + /** + * Get the current subject + * */ + public Subject getSubject(); + + /** + * Get the token manager + * */ + public TokenManager getTokenManager(); +} From ea13c664d20c82fdc18f234e19772b5d8a9aab23 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Sun, 23 Apr 2023 10:25:02 -0400 Subject: [PATCH 2/2] Use identity service to issue token Signed-off-by: Craig Perkins --- .../extensions/ExtensionsManager.java | 9 ++++++++- .../rest/RestActionsRequestHandler.java | 9 +++++++-- .../rest/RestSendToExtensionAction.java | 14 +++++++++----- .../main/java/org/opensearch/node/Node.java | 1 + .../extensions/ExtensionsManagerTests.java | 4 ++++ .../rest/RestSendToExtensionActionTests.java | 19 +++++++++++++------ 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java index 5dc842533152c..dcc7e9bac763e 100644 --- a/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java +++ b/server/src/main/java/org/opensearch/extensions/ExtensionsManager.java @@ -165,13 +165,20 @@ public void initializeServicesAndRestHandler( SettingsModule settingsModule, TransportService transportService, ClusterService clusterService, + IdentityService identityService, Settings initialEnvironmentSettings, NodeClient client ) { - this.restActionsRequestHandler = new RestActionsRequestHandler(actionModule.getRestController(), extensionIdMap, transportService); + this.restActionsRequestHandler = new RestActionsRequestHandler( + actionModule.getRestController(), + extensionIdMap, + transportService, + identityService + ); this.customSettingsRequestHandler = new CustomSettingsRequestHandler(settingsModule); this.transportService = transportService; this.clusterService = clusterService; + this.identityService = identityService; this.environmentSettings = initialEnvironmentSettings; this.addSettingsUpdateConsumerRequestHandler = new AddSettingsUpdateConsumerRequestHandler( clusterService, diff --git a/server/src/main/java/org/opensearch/extensions/rest/RestActionsRequestHandler.java b/server/src/main/java/org/opensearch/extensions/rest/RestActionsRequestHandler.java index 790beaef0a969..fbb116adebc05 100644 --- a/server/src/main/java/org/opensearch/extensions/rest/RestActionsRequestHandler.java +++ b/server/src/main/java/org/opensearch/extensions/rest/RestActionsRequestHandler.java @@ -10,6 +10,7 @@ import org.opensearch.extensions.AcknowledgedResponse; import org.opensearch.extensions.DiscoveryExtensionNode; +import org.opensearch.identity.IdentityService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; import org.opensearch.transport.TransportResponse; @@ -28,6 +29,8 @@ public class RestActionsRequestHandler { private final Map extensionIdMap; private final TransportService transportService; + private final IdentityService identityService; + /** * Instantiates a new REST Actions Request Handler using the Node's RestController. * @@ -38,11 +41,13 @@ public class RestActionsRequestHandler { public RestActionsRequestHandler( RestController restController, Map extensionIdMap, - TransportService transportService + TransportService transportService, + IdentityService identityService ) { this.restController = restController; this.extensionIdMap = extensionIdMap; this.transportService = transportService; + this.identityService = identityService; } /** @@ -54,7 +59,7 @@ public RestActionsRequestHandler( */ public TransportResponse handleRegisterRestActionsRequest(RegisterRestActionsRequest restActionsRequest) throws Exception { DiscoveryExtensionNode discoveryExtensionNode = extensionIdMap.get(restActionsRequest.getUniqueId()); - RestHandler handler = new RestSendToExtensionAction(restActionsRequest, discoveryExtensionNode, transportService); + RestHandler handler = new RestSendToExtensionAction(restActionsRequest, discoveryExtensionNode, transportService, identityService); restController.registerHandler(handler); return new AcknowledgedResponse(true); } diff --git a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java index 9c2f77d4053d3..96166bf547c26 100644 --- a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java +++ b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java @@ -16,6 +16,8 @@ import org.opensearch.common.xcontent.XContentType; import org.opensearch.extensions.DiscoveryExtensionNode; import org.opensearch.extensions.ExtensionsManager; +import org.opensearch.identity.IdentityService; +import org.opensearch.identity.tokens.AuthToken; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestRequest; @@ -64,6 +66,7 @@ public String getName() { private final String pathPrefix; private final DiscoveryExtensionNode discoveryExtensionNode; private final TransportService transportService; + private final IdentityService identityService; private static final Set allowList = Set.of("Content-Type"); private static final Set denyList = Set.of("Authorization", "Proxy-Authorization"); @@ -78,7 +81,8 @@ public String getName() { public RestSendToExtensionAction( RegisterRestActionsRequest restActionsRequest, DiscoveryExtensionNode discoveryExtensionNode, - TransportService transportService + TransportService transportService, + IdentityService identityService ) { this.pathPrefix = "/_extensions/_" + restActionsRequest.getUniqueId(); RestRequest.Method method; @@ -118,6 +122,7 @@ public RestSendToExtensionAction( this.discoveryExtensionNode = discoveryExtensionNode; this.transportService = transportService; + this.identityService = identityService; } @Override @@ -207,9 +212,8 @@ public String executor() { }; try { - // Will be replaced with ExtensionTokenProcessor and PrincipalIdentifierToken classes from feature/identity - final String extensionTokenProcessor = "placeholder_token_processor"; - final String requestIssuerIdentity = "placeholder_request_issuer_identity"; + final AuthToken accessToken = identityService.getTokenManager() + .issueAccessTokenOnBehalfOfAuthenticatedUser(discoveryExtensionNode.getId()); Map> filteredHeaders = filterHeaders(headers, allowList, denyList); @@ -226,7 +230,7 @@ public String executor() { filteredHeaders, contentType, content, - requestIssuerIdentity, + accessToken.getTokenValue(), httpVersion ), restExecuteOnExtensionResponseHandler diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 8e923e53e2dc0..6397fcf2dbcb5 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -875,6 +875,7 @@ protected Node( settingsModule, transportService, clusterService, + identityService, environment.settings(), client ); diff --git a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java index 9d60e8ad31873..831d5a7cba1d5 100644 --- a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java +++ b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java @@ -70,6 +70,7 @@ import org.opensearch.extensions.proto.ExtensionRequestProto; import org.opensearch.extensions.rest.RegisterRestActionsRequest; import org.opensearch.extensions.settings.RegisterCustomSettingsRequest; +import org.opensearch.identity.IdentityService; import org.opensearch.index.IndexModule; import org.opensearch.index.IndexSettings; import org.opensearch.index.analysis.AnalysisRegistry; @@ -100,6 +101,7 @@ public class ExtensionsManagerTests extends OpenSearchTestCase { private RestController restController; private SettingsModule settingsModule; private ClusterService clusterService; + private IdentityService identityService; private NodeClient client; private MockNioTransport transport; private Path extensionDir; @@ -823,6 +825,7 @@ public void testRegisterHandler() throws Exception { settingsModule, mockTransportService, clusterService, + identityService, settings, client ); @@ -903,6 +906,7 @@ private void initialize(ExtensionsManager extensionsManager) { settingsModule, transportService, clusterService, + identityService, settings, client ); diff --git a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java index b98b4955ff75e..126ba0c2219f8 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java @@ -32,6 +32,8 @@ import org.opensearch.common.transport.TransportAddress; import org.opensearch.common.util.PageCacheRecycler; import org.opensearch.extensions.DiscoveryExtensionNode; +import org.opensearch.identity.IdentityService; +import org.opensearch.identity.noop.NoopIdentityPlugin; import org.opensearch.indices.breaker.NoneCircuitBreakerService; import org.opensearch.rest.RestHandler.Route; import org.opensearch.rest.RestRequest.Method; @@ -45,6 +47,7 @@ public class RestSendToExtensionActionTests extends OpenSearchTestCase { private TransportService transportService; + private IdentityService identityService; private MockNioTransport transport; private DiscoveryExtensionNode discoveryExtensionNode; private final ThreadPool threadPool = new TestThreadPool(RestSendToExtensionActionTests.class.getSimpleName()); @@ -86,6 +89,8 @@ public void setup() throws Exception { Version.fromString("3.0.0"), Collections.emptyList() ); + + identityService = new IdentityService(Settings.EMPTY, List.of(new NoopIdentityPlugin())); } @Override @@ -105,7 +110,8 @@ public void testRestSendToExtensionAction() throws Exception { RestSendToExtensionAction restSendToExtensionAction = new RestSendToExtensionAction( registerRestActionRequest, discoveryExtensionNode, - transportService + transportService, + identityService ); assertEquals("send_to_extension_action", restSendToExtensionAction.getName()); @@ -136,7 +142,8 @@ public void testRestSendToExtensionActionFilterHeaders() throws Exception { RestSendToExtensionAction restSendToExtensionAction = new RestSendToExtensionAction( registerRestActionRequest, discoveryExtensionNode, - transportService + transportService, + identityService ); Map> headers = new HashMap<>(); @@ -162,7 +169,7 @@ public void testRestSendToExtensionActionBadMethod() throws Exception { ); expectThrows( IllegalArgumentException.class, - () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService) + () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService, identityService) ); } @@ -174,7 +181,7 @@ public void testRestSendToExtensionActionBadDeprecatedMethod() throws Exception ); expectThrows( IllegalArgumentException.class, - () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService) + () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService, identityService) ); } @@ -186,7 +193,7 @@ public void testRestSendToExtensionActionMissingUri() throws Exception { ); expectThrows( IllegalArgumentException.class, - () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService) + () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService, identityService) ); } @@ -198,7 +205,7 @@ public void testRestSendToExtensionActionMissingDeprecatedUri() throws Exception ); expectThrows( IllegalArgumentException.class, - () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService) + () -> new RestSendToExtensionAction(registerRestActionRequest, discoveryExtensionNode, transportService, identityService) ); } }