diff --git a/src/main/java/org/opensearch/sdk/ExtensionSettings.java b/src/main/java/org/opensearch/sdk/ExtensionSettings.java index 52f08ce63..5372cdc56 100644 --- a/src/main/java/org/opensearch/sdk/ExtensionSettings.java +++ b/src/main/java/org/opensearch/sdk/ExtensionSettings.java @@ -21,6 +21,7 @@ import org.yaml.snakeyaml.Yaml; +import static org.opensearch.sdk.ssl.SSLConfigConstants.SSL_HTTP_ENABLED; import static org.opensearch.sdk.ssl.SSLConfigConstants.SSL_TRANSPORT_CLIENT_PEMCERT_FILEPATH; import static org.opensearch.sdk.ssl.SSLConfigConstants.SSL_TRANSPORT_CLIENT_PEMKEY_FILEPATH; import static org.opensearch.sdk.ssl.SSLConfigConstants.SSL_TRANSPORT_CLIENT_PEMTRUSTEDCAS_FILEPATH; @@ -62,6 +63,7 @@ public class ExtensionSettings { */ public static final Set SECURITY_SETTINGS_KEYS = Set.of( "path.home", // TODO Find the right place to put this setting + SSL_HTTP_ENABLED, SSL_TRANSPORT_CLIENT_PEMCERT_FILEPATH, SSL_TRANSPORT_CLIENT_PEMKEY_FILEPATH, SSL_TRANSPORT_CLIENT_PEMTRUSTEDCAS_FILEPATH, diff --git a/src/main/java/org/opensearch/sdk/ExtensionsRunner.java b/src/main/java/org/opensearch/sdk/ExtensionsRunner.java index 8cdf91b59..ce789b51f 100644 --- a/src/main/java/org/opensearch/sdk/ExtensionsRunner.java +++ b/src/main/java/org/opensearch/sdk/ExtensionsRunner.java @@ -17,8 +17,10 @@ import org.apache.logging.log4j.Logger; import org.opensearch.action.ActionType; import org.opensearch.action.support.TransportAction; +import org.opensearch.client.opensearch.OpenSearchClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.discovery.InitializeExtensionSecurityRequest; import org.opensearch.extensions.rest.ExtensionRestRequest; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; @@ -125,6 +127,7 @@ public class ExtensionsRunner { private final SDKNamedXContentRegistry sdkNamedXContentRegistry; private final SDKNamedWriteableRegistry sdkNamedWriteableRegistry; private final SDKClient sdkClient; + private OpenSearchClient extensionRestClient; private final SDKClusterService sdkClusterService; private final SDKTransportService sdkTransportService; private final SDKActionModule sdkActionModule; @@ -344,6 +347,20 @@ public void setExtensionNode(DiscoveryExtensionNode extensionNode) { this.extensionNode = extensionNode; } + /** + * Initializes a REST Client for this extension to interact with an OpenSearch cluster on its own behalf + * + * @param serviceAccountToken Access token that permits an extension to make requests on its own behalf. + * Common examples of usages of service account tokens include interacting with + * an extension's reserved indices. + */ + public void initializeExtensionRestClient(String serviceAccountToken) { + OpenSearchClient restClient = getSdkClient().initializeJavaClientWithHeaders( + Map.of("Authorization", "Bearer " + serviceAccountToken) + ); + this.extensionRestClient = restClient; + } + /** * Returns the discovery extension node set during extension initialization * @@ -403,6 +420,15 @@ public void startTransportService(TransportService transportService) { (request, channel, task) -> channel.sendResponse(extensionsInitRequestHandler.handleExtensionInitRequest(request)) ); + transportService.registerRequestHandler( + ExtensionsManager.REQUEST_EXTENSION_REGISTER_SECURITY_SETTINGS, + ThreadPool.Names.GENERIC, + false, + false, + InitializeExtensionSecurityRequest::new, + (request, channel, task) -> channel.sendResponse(extensionsInitRequestHandler.handleExtensionSecurityInitRequest(request)) + ); + transportService.registerRequestHandler( ExtensionsManager.REQUEST_REST_EXECUTE_ON_EXTENSION_ACTION, ThreadPool.Names.GENERIC, @@ -528,6 +554,15 @@ public SDKClient getSdkClient() { return sdkClient; } + /** + * Returns the Extension rest client instance used by this extension. + * + * @return The Extension rest client instance. + */ + public OpenSearchClient getExtensionRestClient() { + return extensionRestClient; + } + /** * @return The SDKClusterService instance associated with this object. */ diff --git a/src/main/java/org/opensearch/sdk/SDKClient.java b/src/main/java/org/opensearch/sdk/SDKClient.java index cde356782..19f61559f 100644 --- a/src/main/java/org/opensearch/sdk/SDKClient.java +++ b/src/main/java/org/opensearch/sdk/SDKClient.java @@ -23,17 +23,19 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.guava.GuavaModule; import org.apache.hc.core5.function.Factory; +import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.nio.ssl.TlsStrategy; import org.apache.hc.core5.reactor.ssl.TlsDetails; import org.apache.hc.core5.ssl.SSLContextBuilder; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.action.ActionType; import org.opensearch.action.admin.cluster.health.ClusterHealthRequest; import org.opensearch.action.admin.cluster.health.ClusterHealthResponse; @@ -95,6 +97,8 @@ import javax.net.ssl.SSLEngine; +import static org.opensearch.sdk.ssl.SSLConfigConstants.SSL_HTTP_ENABLED; + /** * This class creates SDKClient for an extension to make requests to OpenSearch */ @@ -164,8 +168,11 @@ public void updateOpenSearchNodeSettings(String address, String httpPort) { * @param port The port the client should connect to * @return An instance of the builder */ - private static RestClientBuilder builder(String hostAddress, int port) { - RestClientBuilder builder = RestClient.builder(new HttpHost(hostAddress, port)); + private static RestClientBuilder builder(String hostAddress, int port, ExtensionSettings extensionSettings) { + boolean httpsEnabled = extensionSettings.getSecuritySettings().containsKey(SSL_HTTP_ENABLED) + && "true".equals(extensionSettings.getSecuritySettings().get(SSL_HTTP_ENABLED)); + String scheme = httpsEnabled ? "https" : "http"; + RestClientBuilder builder = RestClient.builder(new HttpHost(scheme, hostAddress, port)); builder.setStrictDeprecationMode(true); builder.setHttpClientConfigCallback(httpClientBuilder -> { try { @@ -201,8 +208,9 @@ public TlsDetails create(final SSLEngine sslEngine) { * @param port The port of OpenSearch cluster * @return The OpenSearchTransport implementation of RestClientTransport. */ - private OpenSearchTransport initializeTransport(String hostAddress, int port) { - RestClientBuilder builder = builder(hostAddress, port); + private OpenSearchTransport initializeTransport(String hostAddress, int port, Map headers) { + RestClientBuilder builder = builder(hostAddress, port, extensionSettings); + builder.setDefaultHeaders(headers.keySet().stream().map(k -> new BasicHeader(k, headers.get(k))).toArray(Header[]::new)); restClient = builder.build(); ObjectMapper mapper = new ObjectMapper(); @@ -227,6 +235,20 @@ public OpenSearchClient initializeJavaClient() { return initializeJavaClient(extensionSettings.getOpensearchAddress(), Integer.parseInt(extensionSettings.getOpensearchPort())); } + /** + * Initializes an OpenSearchClient using OpenSearch JavaClient + * + * @return The SDKClient implementation of OpenSearchClient. The user is responsible for calling + * {@link #doCloseJavaClients()} when finished with the client + */ + public OpenSearchClient initializeJavaClientWithHeaders(Map headers) { + return initializeJavaClientWithHeaders( + extensionSettings.getOpensearchAddress(), + Integer.parseInt(extensionSettings.getOpensearchPort()), + headers + ); + } + /** * Initializes an OpenSearchClient using OpenSearch JavaClient * @@ -236,7 +258,21 @@ public OpenSearchClient initializeJavaClient() { * {@link #doCloseJavaClients()} when finished with the client */ public OpenSearchClient initializeJavaClient(String hostAddress, int port) { - OpenSearchTransport transport = initializeTransport(hostAddress, port); + OpenSearchTransport transport = initializeTransport(hostAddress, port, Map.of()); + javaClient = new OpenSearchClient(transport); + return javaClient; + } + + /** + * Initializes an OpenSearchClient using OpenSearch JavaClient + * + * @param hostAddress The address of OpenSearch cluster, client can connect to + * @param port The port of OpenSearch cluster + * @return The SDKClient implementation of OpenSearchClient. The user is responsible for calling + * {@link #doCloseJavaClients()} when finished with the client + */ + public OpenSearchClient initializeJavaClientWithHeaders(String hostAddress, int port, Map headers) { + OpenSearchTransport transport = initializeTransport(hostAddress, port, headers); javaClient = new OpenSearchClient(transport); return javaClient; } @@ -260,7 +296,7 @@ public OpenSearchAsyncClient initializeJavaAsyncClient() { * {@link #doCloseJavaClients()} when finished with the client */ public OpenSearchAsyncClient initalizeJavaAsyncClient(String hostAddress, int port) { - OpenSearchTransport transport = initializeTransport(hostAddress, port); + OpenSearchTransport transport = initializeTransport(hostAddress, port, Map.of()); javaAsyncClient = new OpenSearchAsyncClient(transport); return javaAsyncClient; } @@ -300,7 +336,7 @@ public SDKRestClient initializeRestClient() { */ @Deprecated public SDKRestClient initializeRestClient(String hostAddress, int port) { - this.sdkRestClient = new SDKRestClient(this, new RestHighLevelClient(builder(hostAddress, port))); + this.sdkRestClient = new SDKRestClient(this, new RestHighLevelClient(builder(hostAddress, port, extensionSettings))); return this.sdkRestClient; } diff --git a/src/main/java/org/opensearch/sdk/SDKTransportService.java b/src/main/java/org/opensearch/sdk/SDKTransportService.java index ac873c739..056e8a7ed 100644 --- a/src/main/java/org/opensearch/sdk/SDKTransportService.java +++ b/src/main/java/org/opensearch/sdk/SDKTransportService.java @@ -26,6 +26,7 @@ import org.opensearch.cluster.node.DiscoveryNode; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; +import org.opensearch.core.transport.TransportResponse; import org.opensearch.extensions.AddSettingsUpdateConsumerRequest; import org.opensearch.extensions.DiscoveryExtensionNode; import org.opensearch.extensions.ExtensionRequest; @@ -47,7 +48,6 @@ import org.opensearch.sdk.handlers.ExtensionDependencyResponseHandler; import org.opensearch.sdk.handlers.UpdateSettingsRequestHandler; import org.opensearch.sdk.rest.ExtensionRestPathRegistry; -import org.opensearch.transport.TransportResponse; import org.opensearch.transport.TransportResponseHandler; import org.opensearch.transport.TransportService; diff --git a/src/main/java/org/opensearch/sdk/action/RemoteExtensionActionRequest.java b/src/main/java/org/opensearch/sdk/action/RemoteExtensionActionRequest.java index 85c7108f5..abf53a238 100644 --- a/src/main/java/org/opensearch/sdk/action/RemoteExtensionActionRequest.java +++ b/src/main/java/org/opensearch/sdk/action/RemoteExtensionActionRequest.java @@ -14,7 +14,7 @@ import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.action.ActionType; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/src/main/java/org/opensearch/sdk/action/RemoteExtensionTransportAction.java b/src/main/java/org/opensearch/sdk/action/RemoteExtensionTransportAction.java index fa9ce8ed1..d6948dbfe 100644 --- a/src/main/java/org/opensearch/sdk/action/RemoteExtensionTransportAction.java +++ b/src/main/java/org/opensearch/sdk/action/RemoteExtensionTransportAction.java @@ -9,7 +9,7 @@ package org.opensearch.sdk.action; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.TransportAction; import org.opensearch.extensions.action.RemoteExtensionActionResponse; diff --git a/src/main/java/org/opensearch/sdk/api/ActionExtension.java b/src/main/java/org/opensearch/sdk/api/ActionExtension.java index 0c807f01d..cd6cb915f 100644 --- a/src/main/java/org/opensearch/sdk/api/ActionExtension.java +++ b/src/main/java/org/opensearch/sdk/api/ActionExtension.java @@ -11,7 +11,7 @@ import org.opensearch.action.ActionType; import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.action.RequestValidators; import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest; import org.opensearch.action.admin.indices.mapping.put.PutMappingRequest; diff --git a/src/main/java/org/opensearch/sdk/handlers/ExtensionActionRequestHandler.java b/src/main/java/org/opensearch/sdk/handlers/ExtensionActionRequestHandler.java index 54e53b2e9..b3b1734d1 100644 --- a/src/main/java/org/opensearch/sdk/handlers/ExtensionActionRequestHandler.java +++ b/src/main/java/org/opensearch/sdk/handlers/ExtensionActionRequestHandler.java @@ -18,9 +18,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.action.ActionType; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.common.io.stream.BytesStreamOutput; diff --git a/src/main/java/org/opensearch/sdk/handlers/ExtensionsInitRequestHandler.java b/src/main/java/org/opensearch/sdk/handlers/ExtensionsInitRequestHandler.java index fc4eb87ad..482ffabce 100644 --- a/src/main/java/org/opensearch/sdk/handlers/ExtensionsInitRequestHandler.java +++ b/src/main/java/org/opensearch/sdk/handlers/ExtensionsInitRequestHandler.java @@ -15,6 +15,8 @@ import org.opensearch.common.settings.Settings; import org.opensearch.discovery.InitializeExtensionRequest; import org.opensearch.discovery.InitializeExtensionResponse; +import org.opensearch.discovery.InitializeExtensionSecurityRequest; +import org.opensearch.discovery.InitializeExtensionSecurityResponse; import org.opensearch.sdk.ExtensionsRunner; import org.opensearch.sdk.SDKTransportService; import org.opensearch.transport.TransportService; @@ -94,4 +96,20 @@ public InitializeExtensionResponse handleExtensionInitRequest(InitializeExtensio extensionsRunner.getSdkClusterService().getClusterSettings().sendPendingSettingsUpdateConsumers(); } } + + /** + * Handles a extension request from OpenSearch. This is the first request for the transport communication and will initialize the extension and will be a part of OpenSearch bootstrap. + * + * @param extensionInitSecurityRequest The request to handle. + * @return A response to OpenSearch validating that this is an extension. + */ + public InitializeExtensionSecurityResponse handleExtensionSecurityInitRequest( + InitializeExtensionSecurityRequest extensionInitSecurityRequest + ) { + logger.info("Registering Extension Request received from OpenSearch"); + + extensionsRunner.initializeExtensionRestClient(extensionInitSecurityRequest.getServiceAccountToken()); + + return new InitializeExtensionSecurityResponse(extensionsRunner.getExtensionNode().getId()); + } } diff --git a/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java b/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java index 88f60b564..7c4a4b026 100644 --- a/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java +++ b/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java @@ -9,6 +9,7 @@ package org.opensearch.sdk.handlers; +import joptsimple.internal.Strings; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.core.common.bytes.BytesReference; @@ -22,6 +23,10 @@ import org.opensearch.sdk.rest.SDKHttpRequest; import org.opensearch.sdk.rest.SDKRestRequest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.emptyMap; import static java.util.Collections.emptyList; @@ -68,11 +73,19 @@ public RestExecuteOnExtensionResponse handleRestExecuteOnExtensionRequest(Extens ); } + String oboToken = request.getRequestIssuerIdentity(); + Map> headers = new HashMap<>(); + headers.putAll(request.headers()); + System.out.println("oboToken: " + oboToken); + if (!Strings.isNullOrEmpty(oboToken)) { + headers.put("Authorization", List.of("Bearer " + oboToken)); + } + SDKRestRequest sdkRestRequest = new SDKRestRequest( sdkNamedXContentRegistry.getRegistry(), request.params(), request.path(), - request.headers(), + headers, new SDKHttpRequest(request), null ); diff --git a/src/main/java/org/opensearch/sdk/handlers/OpensearchRequestHandler.java b/src/main/java/org/opensearch/sdk/handlers/OpensearchRequestHandler.java index 53da0420e..64d145e74 100644 --- a/src/main/java/org/opensearch/sdk/handlers/OpensearchRequestHandler.java +++ b/src/main/java/org/opensearch/sdk/handlers/OpensearchRequestHandler.java @@ -9,9 +9,9 @@ package org.opensearch.sdk.handlers; +import org.opensearch.core.transport.TransportResponse; import org.opensearch.extensions.OpenSearchRequest; import org.opensearch.sdk.ExtensionsRunner; -import org.opensearch.transport.TransportResponse; /** * This class handles the request from OpenSearch to a {@link ExtensionsRunner#startTransportService(TransportService transportService)} call. diff --git a/src/main/java/org/opensearch/sdk/rest/BaseExtensionRestHandler.java b/src/main/java/org/opensearch/sdk/rest/BaseExtensionRestHandler.java index dc39eab23..3473c33a7 100644 --- a/src/main/java/org/opensearch/sdk/rest/BaseExtensionRestHandler.java +++ b/src/main/java/org/opensearch/sdk/rest/BaseExtensionRestHandler.java @@ -11,7 +11,9 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -25,6 +27,7 @@ import static org.apache.hc.core5.http.ContentType.APPLICATION_JSON; import org.opensearch.OpenSearchException; +import org.opensearch.client.opensearch.OpenSearchClient; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.core.common.Strings; @@ -38,6 +41,7 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.rest.RestResponse; import org.opensearch.core.rest.RestStatus; +import org.opensearch.sdk.SDKClient; /** * Provides convenience methods to reduce boilerplate code in an {@link ExtensionRestHandler} implementation. @@ -48,6 +52,14 @@ public abstract class BaseExtensionRestHandler implements ExtensionRestHandler { private String routeNamePrefix; + private SDKClient sdkClient; + + protected OpenSearchClient userRestClient; + + public BaseExtensionRestHandler(SDKClient sdkClient) { + this.sdkClient = sdkClient; + } + /** * Constant for JSON content type */ @@ -114,6 +126,15 @@ public List replacedRoutes() { @Override public ExtensionRestResponse handleRequest(RestRequest request) { + if (request instanceof SDKRestRequest) { + SDKRestRequest sdkRestRequest = (SDKRestRequest) request; + List authorizationHeaders = sdkRestRequest.getHeaders().get("Authorization"); + Map headers = new HashMap<>(); + if (!authorizationHeaders.isEmpty()) { + headers.put("Authorization", authorizationHeaders.get(0)); + } + this.userRestClient = sdkClient.initializeJavaClientWithHeaders(headers); + } Optional route = routes().stream() .filter(rh -> rh.getMethod().equals(request.method())) .filter(rh -> restPathMatches(request.path(), rh.getPath())) diff --git a/src/main/java/org/opensearch/sdk/sample/helloworld/HelloWorldExtension.java b/src/main/java/org/opensearch/sdk/sample/helloworld/HelloWorldExtension.java index f4b8566dd..5f74d8a5c 100644 --- a/src/main/java/org/opensearch/sdk/sample/helloworld/HelloWorldExtension.java +++ b/src/main/java/org/opensearch/sdk/sample/helloworld/HelloWorldExtension.java @@ -14,7 +14,7 @@ import java.util.List; import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.common.settings.Setting; import org.opensearch.sdk.BaseExtension; import org.opensearch.sdk.Extension; @@ -56,7 +56,7 @@ public HelloWorldExtension() { @Override public List getExtensionRestHandlers() { - return List.of(new RestHelloAction(), new RestRemoteHelloAction(extensionsRunner())); + return List.of(new RestHelloAction(extensionsRunner().getSdkClient()), new RestRemoteHelloAction(extensionsRunner())); } @Override diff --git a/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestHelloAction.java b/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestHelloAction.java index 122245b3e..6f083aeda 100644 --- a/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestHelloAction.java +++ b/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestHelloAction.java @@ -19,6 +19,7 @@ import org.opensearch.rest.NamedRoute; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; +import org.opensearch.sdk.SDKClient; import org.opensearch.sdk.rest.BaseExtensionRestHandler; import org.opensearch.sdk.rest.ExtensionRestHandler; @@ -49,7 +50,7 @@ public class RestHelloAction extends BaseExtensionRestHandler { private static final String TEXT_CONTENT_TYPE = "text/plain; charset=UTF-8"; - private static final String GREETING = "Hello, %s!"; + public static final String GREETING = "Hello, %s!"; private static final String DEFAULT_NAME = "World"; private String worldName = DEFAULT_NAME; @@ -59,7 +60,9 @@ public class RestHelloAction extends BaseExtensionRestHandler { /** * Instantiate this action */ - public RestHelloAction() {} + public RestHelloAction(SDKClient sdkClient) { + super(sdkClient); + } @Override public List routes() { diff --git a/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestRemoteHelloAction.java b/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestRemoteHelloAction.java index 7bda7ff19..1f52601f5 100644 --- a/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestRemoteHelloAction.java +++ b/src/main/java/org/opensearch/sdk/sample/helloworld/rest/RestRemoteHelloAction.java @@ -9,7 +9,11 @@ package org.opensearch.sdk.sample.helloworld.rest; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; +import org.opensearch.client.WarningFailureException; +import org.opensearch.client.opensearch.OpenSearchClient; +import org.opensearch.client.opensearch.indices.CreateIndexRequest; +import org.opensearch.client.opensearch.indices.DeleteIndexRequest; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.extensions.ExtensionsManager; import org.opensearch.extensions.action.RemoteExtensionActionResponse; @@ -26,14 +30,19 @@ import org.opensearch.sdk.sample.helloworld.transport.SampleRequest; import org.opensearch.sdk.sample.helloworld.transport.SampleResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Function; import static org.opensearch.rest.RestRequest.Method.GET; import static org.opensearch.core.rest.RestStatus.OK; +import static org.opensearch.sdk.sample.helloworld.rest.RestHelloAction.GREETING; /** * Sample REST Handler demonstrating proxy actions to another extension @@ -48,6 +57,7 @@ public class RestRemoteHelloAction extends BaseExtensionRestHandler { * @param runner The ExtensionsRunner instance */ public RestRemoteHelloAction(ExtensionsRunner runner) { + super(runner.getSdkClient()); this.extensionsRunner = runner; } @@ -60,6 +70,18 @@ public List routes() { .handler(handleRemoteGetRequest) .uniqueName(addRouteNamePrefix("remote_greet_with_name")) .legacyActionNames(Collections.emptySet()) + .build(), + new NamedRoute.Builder().method(GET) + .path("/greet/{name}") + .handler(handleLocalGetRequest) + .uniqueName(addRouteNamePrefix("local_greet_with_name")) + .legacyActionNames(Collections.emptySet()) + .build(), + new NamedRoute.Builder().method(GET) + .path("/service_account_token_example") + .handler(handleServiceAccountTokenExampleRequest) + .uniqueName(addRouteNamePrefix("service_account_token_example")) + .legacyActionNames(Collections.emptySet()) .build() ); } @@ -101,4 +123,111 @@ public List routes() { } }; + private Function handleLocalGetRequest = (request) -> { + // Example usage of userRestClient + try { + userRestClient.indices().create(new CreateIndexRequest.Builder().index(".my-index").build()); + } catch (IOException e) { + System.out.println(e.getMessage()); + } catch (WarningFailureException e2) { + System.out.println(e2.getMessage()); + } + + String name = request.param("name"); + + return new ExtensionRestResponse(request, OK, String.format(GREETING, name)); + }; + + private Function handleServiceAccountTokenExampleRequest = (request) -> { + // Uncomment the lines below to try out different actions utilizing the service account token + + OpenSearchClient adminRestClient = extensionsRunner.getSdkClient() + .initializeJavaClientWithHeaders( + Map.of("Authorization", "Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8))) + ); + + try { + adminRestClient.indices().create(new CreateIndexRequest.Builder().index(".hello-world-jobs").build()); + } catch (IOException e) { + System.out.println(e.getMessage()); + } catch (WarningFailureException e2) { + System.out.println(e2.getMessage()); + } + + // Example usage of extension rest client - utilizing service account token + try { + extensionsRunner.getExtensionRestClient().indices().delete(new DeleteIndexRequest.Builder().index(".hello-world-jobs").build()); + } catch (IOException e) { + System.out.println(e.getMessage()); + } catch (WarningFailureException e2) { + System.out.println(e2.getMessage()); + } + + // Try reading from index with service account token + + // try { + // adminRestClient.indices().create(new CreateIndexRequest.Builder().index("logs-123").build()); + // } catch (IOException e) { + // System.out.println(e.getMessage()); + // } catch (WarningFailureException e2) { + // System.out.println(e2.getMessage()); + // } + // + // try { + // SearchRequest searchRequest = new SearchRequest.Builder() + // .index("logs-123") + // .build(); + // SearchResponse searchResponse = userRestClient.search(searchRequest, JsonNode.class); + // System.out.println("SearchResponse: " + searchResponse); + // } catch (IOException e) { + // System.out.println(e.getMessage()); + // } catch (WarningFailureException e2) { + // System.out.println(e2.getMessage()); + // } + // + // try { + // IndexData indexData = new IndexData("John", "Doe"); + // IndexRequest indexRequest = new + // IndexRequest.Builder().index("logs-123").id("1").document(indexData).build(); + // userRestClient.index(indexRequest); + // } catch (IOException e) { + // System.out.println(e.getMessage()); + // } catch (WarningFailureException e2) { + // System.out.println(e2.getMessage()); + // } + + return new ExtensionRestResponse(request, OK, String.format(GREETING, "World")); + }; + + static class IndexData { + private String firstName; + private String lastName; + + public IndexData(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return String.format("IndexData{first name='%s', last name='%s'}", firstName, lastName); + } + } + } diff --git a/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleResponse.java b/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleResponse.java index 8d3f9b1ea..f6be89f16 100644 --- a/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleResponse.java +++ b/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleResponse.java @@ -11,7 +11,7 @@ import java.io.IOException; -import org.opensearch.action.ActionResponse; +import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; diff --git a/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleTransportAction.java b/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleTransportAction.java index 2c80f1cfd..894dd3c64 100644 --- a/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleTransportAction.java +++ b/src/main/java/org/opensearch/sdk/sample/helloworld/transport/SampleTransportAction.java @@ -9,7 +9,7 @@ package org.opensearch.sdk.sample.helloworld.transport; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; import org.opensearch.action.support.ActionFilters; import org.opensearch.action.support.TransportAction; import org.opensearch.tasks.Task; diff --git a/src/main/java/org/opensearch/sdk/ssl/SSLConfigConstants.java b/src/main/java/org/opensearch/sdk/ssl/SSLConfigConstants.java index c57357613..3122b6437 100644 --- a/src/main/java/org/opensearch/sdk/ssl/SSLConfigConstants.java +++ b/src/main/java/org/opensearch/sdk/ssl/SSLConfigConstants.java @@ -19,6 +19,7 @@ * Class containing constants for SSL */ public final class SSLConfigConstants { + public static final String SSL_HTTP_ENABLED = "ssl.http.enabled"; public static final String SSL_TRANSPORT_ENABLED = "ssl.transport.enabled"; // TODO Replace this with true when security changes are complete public static final boolean SSL_TRANSPORT_ENABLED_DEFAULT = false; diff --git a/src/main/resources/sample/helloworld-settings.yml b/src/main/resources/sample/helloworld-settings.yml index 15cdbdcfb..6b8a4836b 100644 --- a/src/main/resources/sample/helloworld-settings.yml +++ b/src/main/resources/sample/helloworld-settings.yml @@ -1,11 +1,12 @@ extensionName: hello-world hostAddress: 127.0.0.1 -hostPort: 4500 +hostPort: 4532 opensearchAddress: 127.0.0.1 opensearchPort: 9200 +#ssl.http.enabled: true #ssl.transport.enabled: true #ssl.transport.pemcert_filepath: certs/extension-01.pem #ssl.transport.pemkey_filepath: certs/extension-01-key.pem #ssl.transport.pemtrustedcas_filepath: certs/root-ca.pem #ssl.transport.enforce_hostname_verification: false -#path.home: +#path.home: /Users/cwperx/Projects/opensearch/opensearch-sdk-java diff --git a/src/test/java/org/opensearch/sdk/TestSDKClient.java b/src/test/java/org/opensearch/sdk/TestSDKClient.java index 0be408f6c..778a9b409 100644 --- a/src/test/java/org/opensearch/sdk/TestSDKClient.java +++ b/src/test/java/org/opensearch/sdk/TestSDKClient.java @@ -10,7 +10,7 @@ package org.opensearch.sdk; import org.junit.jupiter.api.Test; -import org.opensearch.action.ActionListener; +import org.opensearch.core.action.ActionListener; import org.opensearch.action.admin.cluster.health.ClusterHealthRequest; import org.opensearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.opensearch.action.admin.indices.alias.get.GetAliasesRequest; diff --git a/src/test/java/org/opensearch/sdk/rest/TestBaseExtensionRestHandler.java b/src/test/java/org/opensearch/sdk/rest/TestBaseExtensionRestHandler.java index cd0e24bfd..772b84cc4 100644 --- a/src/test/java/org/opensearch/sdk/rest/TestBaseExtensionRestHandler.java +++ b/src/test/java/org/opensearch/sdk/rest/TestBaseExtensionRestHandler.java @@ -23,13 +23,17 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.rest.RestResponse; import org.opensearch.core.rest.RestStatus; +import org.opensearch.sdk.ExtensionSettings; +import org.opensearch.sdk.SDKClient; import org.opensearch.test.OpenSearchTestCase; import static org.opensearch.rest.RestRequest.Method.GET; public class TestBaseExtensionRestHandler extends OpenSearchTestCase { - private final BaseExtensionRestHandler handler = new BaseExtensionRestHandler() { + private final ExtensionSettings extensionSettings = new ExtensionSettings("", "", "", "localhost", "9200"); + private final SDKClient sdkClient = new SDKClient(extensionSettings); + private final BaseExtensionRestHandler handler = new BaseExtensionRestHandler(sdkClient) { @Override public List routes() { return List.of( @@ -80,7 +84,7 @@ public List replacedRouteHandlers() { @Test public void testHandlerDefaultRoutes() { - BaseExtensionRestHandler defaultHandler = new BaseExtensionRestHandler() { + BaseExtensionRestHandler defaultHandler = new BaseExtensionRestHandler(sdkClient) { }; assertTrue(defaultHandler.routes().isEmpty()); } @@ -287,7 +291,7 @@ public void testErrorResponseOnUnhandled() { @Test public void testCreateEmptyJsonResponse() { - BaseExtensionRestHandler handlerWithEmptyJsonResponse = new BaseExtensionRestHandler() { + BaseExtensionRestHandler handlerWithEmptyJsonResponse = new BaseExtensionRestHandler(sdkClient) { @Override public List routes() { return List.of( diff --git a/src/test/java/org/opensearch/sdk/rest/TestExtensionRestPathRegistry.java b/src/test/java/org/opensearch/sdk/rest/TestExtensionRestPathRegistry.java index 008214d03..da7c9f944 100644 --- a/src/test/java/org/opensearch/sdk/rest/TestExtensionRestPathRegistry.java +++ b/src/test/java/org/opensearch/sdk/rest/TestExtensionRestPathRegistry.java @@ -21,6 +21,8 @@ import org.opensearch.rest.RestHandler.ReplacedRoute; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; +import org.opensearch.sdk.ExtensionSettings; +import org.opensearch.sdk.SDKClient; import org.opensearch.sdk.rest.BaseExtensionRestHandler.ExtensionDeprecationRestHandler; import org.opensearch.test.OpenSearchTestCase; @@ -44,7 +46,9 @@ public ExtensionRestResponse handleRequest(RestRequest request) { return null; } }; - private BaseExtensionRestHandler replacedFooHandler = new BaseExtensionRestHandler() { + + private final ExtensionSettings extensionSettings = new ExtensionSettings("", "", "", "localhost", "9200"); + private BaseExtensionRestHandler replacedFooHandler = new BaseExtensionRestHandler(new SDKClient(extensionSettings)) { @Override public List replacedRoutes() { return List.of( diff --git a/src/test/java/org/opensearch/sdk/sample/helloworld/rest/TestRestHelloAction.java b/src/test/java/org/opensearch/sdk/sample/helloworld/rest/TestRestHelloAction.java index 09c5c96f2..0ccb66069 100644 --- a/src/test/java/org/opensearch/sdk/sample/helloworld/rest/TestRestHelloAction.java +++ b/src/test/java/org/opensearch/sdk/sample/helloworld/rest/TestRestHelloAction.java @@ -25,6 +25,8 @@ import org.opensearch.http.HttpRequest.HttpVersion; import org.opensearch.rest.RestResponse; import org.opensearch.core.rest.RestStatus; +import org.opensearch.sdk.ExtensionSettings; +import org.opensearch.sdk.SDKClient; import org.opensearch.sdk.rest.ExtensionRestHandler; import org.opensearch.sdk.rest.TestSDKRestRequest; import org.opensearch.test.OpenSearchTestCase; @@ -34,6 +36,9 @@ public class TestRestHelloAction extends OpenSearchTestCase { private static final String TEXT_CONTENT_TYPE = "text/plain; charset=UTF-8"; private static final String JSON_CONTENT_TYPE = "application/json; charset=UTF-8"; + private final ExtensionSettings extensionSettings = new ExtensionSettings("", "", "", "localhost", "9200"); + private final SDKClient sdkClient = new SDKClient(extensionSettings); + private ExtensionRestHandler restHelloAction; // Temporarily removed pending integration of feature/identity branch // private static final String EXTENSION_NAME = "hello-world"; @@ -42,7 +47,7 @@ public class TestRestHelloAction extends OpenSearchTestCase { @BeforeEach public void setUp() throws Exception { super.setUp(); - restHelloAction = new RestHelloAction(); + restHelloAction = new RestHelloAction(sdkClient); } @Test