Skip to content

Commit

Permalink
Fix integration test failure with secured cluster (#115) (#138)
Browse files Browse the repository at this point in the history
Signed-off-by: Heemin Kim <heemin@amazon.com>
  • Loading branch information
heemin32 authored Sep 12, 2022
1 parent 2026f51 commit 89b676a
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@
import org.opensearch.geospatial.rest.action.upload.geojson.RestUploadGeoJSONAction;
import org.opensearch.ingest.Pipeline;
import org.opensearch.rest.RestStatus;
import org.opensearch.test.rest.OpenSearchRestTestCase;

public abstract class GeospatialRestTestCase extends OpenSearchRestTestCase {
public abstract class GeospatialRestTestCase extends OpenSearchSecureRestTestCase {

public static final String SOURCE = "_source";
public static final String DOC = "_doc";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* 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.geospatial;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.After;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.client.RestClient;
import org.opensearch.client.RestClientBuilder;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.unit.TimeValue;
import org.opensearch.common.util.concurrent.ThreadContext;
import org.opensearch.common.xcontent.DeprecationHandler;
import org.opensearch.common.xcontent.NamedXContentRegistry;
import org.opensearch.common.xcontent.XContentParser;
import org.opensearch.common.xcontent.XContentType;
import org.opensearch.test.rest.OpenSearchRestTestCase;

/**
* Integration test base class to support both security disabled and enabled OpenSearch cluster.
*/
public abstract class OpenSearchSecureRestTestCase extends OpenSearchRestTestCase {
private static final String PROTOCOL_HTTP = "http";
private static final String PROTOCOL_HTTPS = "https";
private static final String SYS_PROPERTY_KEY_HTTPS = "https";
private static final String SYS_PROPERTY_KEY_CLUSTER_ENDPOINT = "tests.rest.cluster";
private static final String SYS_PROPERTY_KEY_USER = "user";
private static final String SYS_PROPERTY_KEY_PASSWORD = "password";
private static final String DEFAULT_SOCKET_TIMEOUT = "60s";
private static final String INTERNAL_INDICES_PREFIX = ".";
private static String protocol;

@Override
protected String getProtocol() {
if (protocol == null) {
protocol = readProtocolFromSystemProperty();
}
return protocol;
}

private String readProtocolFromSystemProperty() {
boolean isHttps = Optional.ofNullable(System.getProperty(SYS_PROPERTY_KEY_HTTPS)).map("true"::equalsIgnoreCase).orElse(false);
if (!isHttps) {
return PROTOCOL_HTTP;
}

// currently only external cluster is supported for security enabled testing
if (Optional.ofNullable(System.getProperty(SYS_PROPERTY_KEY_CLUSTER_ENDPOINT)).isEmpty()) {
throw new RuntimeException("cluster url should be provided for security enabled testing");
}
return PROTOCOL_HTTPS;
}

@Override
protected RestClient buildClient(Settings settings, HttpHost[] hosts) throws IOException {
RestClientBuilder builder = RestClient.builder(hosts);
if (PROTOCOL_HTTPS.equals(getProtocol())) {
configureHttpsClient(builder, settings);
} else {
configureClient(builder, settings);
}

return builder.build();
}

private void configureHttpsClient(RestClientBuilder builder, Settings settings) {
Map<String, String> headers = ThreadContext.buildDefaultHeaders(settings);
Header[] defaultHeaders = new Header[headers.size()];
int i = 0;
for (Map.Entry<String, String> entry : headers.entrySet()) {
defaultHeaders[i++] = new BasicHeader(entry.getKey(), entry.getValue());
}
builder.setDefaultHeaders(defaultHeaders);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
String userName = Optional.ofNullable(System.getProperty(SYS_PROPERTY_KEY_USER))
.orElseThrow(() -> new RuntimeException("user name is missing"));
String password = Optional.ofNullable(System.getProperty(SYS_PROPERTY_KEY_PASSWORD))
.orElseThrow(() -> new RuntimeException("password is missing"));
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));
try {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
// disable the certificate since our testing cluster just uses the default security configuration
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setSSLContext(SSLContextBuilder.create().loadTrustMaterial(null, (chains, authType) -> true).build());
} catch (Exception e) {
throw new RuntimeException(e);
}
});

final String socketTimeoutString = settings.get(CLIENT_SOCKET_TIMEOUT);
final TimeValue socketTimeout = TimeValue.parseTimeValue(
socketTimeoutString == null ? DEFAULT_SOCKET_TIMEOUT : socketTimeoutString,
CLIENT_SOCKET_TIMEOUT
);
builder.setRequestConfigCallback(conf -> conf.setSocketTimeout(Math.toIntExact(socketTimeout.getMillis())));
if (settings.hasValue(CLIENT_PATH_PREFIX)) {
builder.setPathPrefix(settings.get(CLIENT_PATH_PREFIX));
}
}

/**
* wipeAllIndices won't work since it cannot delete security index. Use deleteExternalIndices instead.
*/
@Override
protected boolean preserveIndicesUponCompletion() {
return true;
}

@After
public void deleteExternalIndices() throws IOException {
Response response = client().performRequest(new Request("GET", "/_cat/indices?format=json&expand_wildcards=all"));
XContentType xContentType = XContentType.fromMediaType(response.getEntity().getContentType().getValue());
try (
XContentParser parser = xContentType.xContent()
.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
response.getEntity().getContent()
)
) {
XContentParser.Token token = parser.nextToken();
List<Map<String, Object>> parserList;
if (token == XContentParser.Token.START_ARRAY) {
parserList = parser.listOrderedMap().stream().map(obj -> (Map<String, Object>) obj).collect(Collectors.toList());
} else {
parserList = Collections.singletonList(parser.mapOrdered());
}

List<String> externalIndices = parserList.stream()
.map(index -> (String) index.get("index"))
.filter(indexName -> indexName != null)
.filter(indexName -> !indexName.startsWith(INTERNAL_INDICES_PREFIX))
.collect(Collectors.toList());

for (String indexName : externalIndices) {
adminClient().performRequest(new Request("DELETE", "/" + indexName));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import org.apache.http.util.EntityUtils;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.geospatial.GeospatialRestTestCase;
import org.opensearch.rest.RestStatus;
import org.opensearch.test.rest.OpenSearchRestTestCase;

public class GeospatialPluginIT extends OpenSearchRestTestCase {
public class GeospatialPluginIT extends GeospatialRestTestCase {

/**
* Tests whether plugin is installed or not
Expand Down

0 comments on commit 89b676a

Please sign in to comment.