ChaosSearch ES API - Java
Java client for the ChaosSearch API
GitHub Repo:
https://github.com/ChaosSearch/JavaAPI/tree/master/aws-request-signing-apache-interceptor
Java API Requests
/*
* Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import java.util.logging.LogManager;
import java.io.IOException;
import java.util.logging.Level;
import java.util.Enumeration;
/**
* <p>An AWS Request Signing Interceptor sample for arbitrary HTTP requests to an Amazon Elasticsearch Service domain.</p>
* <p>The interceptor can also be used with the Elasticsearch REST clients for additional convenience and serialization.</p>
* <p>Example usage with the Elasticsearch low-level REST client:</p>
* <pre>
* String serviceName = "es";
* AWS4Signer signer = new AWS4Signer();
* signer.setServiceName(serviceName);
* signer.setRegionName("us-east-1");
*
* HttpRequestInterceptor interceptor =
* new AWSRequestSigningApacheInterceptor(serviceName, signer, credentialsProvider);
*
* return RestClient
* .builder(HttpHost.create("https://search-my-es-endpoint-gjhfgfhgfhg.us-east-1.amazonaws.com"))
* .setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor))
* .build();
* </pre>
* <p>Example usage with the Elasticsearch high-level REST client:</p>
* <pre>
* String serviceName = "es";
* AWS4Signer signer = new AWS4Signer();
* signer.setServiceName(serviceName);
* signer.setRegionName("us-east-1");
*
* HttpRequestInterceptor interceptor =
* new AWSRequestSigningApacheInterceptor(serviceName, signer, credentialsProvider);
*
* return new RestHighLevelClient(RestClient
* .builder(HttpHost.create("https://search-my-es-endpoint-gjhfgfhgfhg.us-east-1.amazonaws.com"))
* .setHttpClientConfigCallback(hacb -> hacb.addInterceptorLast(interceptor)));
* </pre>
*/
public class AmazonElasticsearchServiceSample extends Sample {
private static final String AES_ENDPOINT = "https://poc-trial.chaossearch.io/elastic/_msearch";
public static void main(String[] args) throws IOException {
AmazonElasticsearchServiceSample aesSample = new AmazonElasticsearchServiceSample();
aesSample.queryCHAOS();
}
private void queryCHAOS() throws IOException {
String payload = "{\"index\":\"dev01-useast1_perflab-05101139_events\",\"ignore_unavailable\":true\"preference\":1574355817948}\n{\"version\":true,\"size\":500,"\"sort\":[{\"_score\":{\"order\":\"desc\"}}],\"_source\":{\"excludes\":[]},\"stored_fields\":[\"*\"],\"script_fields\":{}," +"\"docvalue_fields\":[{\"field\":\"created\",\"format\":\"date_time\"}],"query\":{\"bool\":{\"must\":[{\"query_string\":{\"query\":\"status:passed\",\"analyze_wildcard\":true,\"time_zone\":\"America/Chicago\"}}],\"filter\":[{\"match_all\":{}}],\"should\":[],\"must_not\":[]}},\"timeout\":\"30000ms\"}";
HttpPost httpPost = new HttpPost(AES_ENDPOINT );
httpPost.setEntity(stringEntity(payload));
httpPost.addHeader("Content-Type", "application/json");
httpPost.removeHeaders("accept-encoding");
httpPost.removeHeaders("transfer-encoding");
logRequest("es", httpPost);
}
}
/*
* Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
package com.amazonaws.http;
import com.amazonaws.DefaultRequest;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.Signer;
import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static org.apache.http.protocol.HttpCoreContext.HTTP_TARGET_HOST;
/**
* An {@link HttpRequestInterceptor} that signs requests using any AWS {@link Signer}
* and {@link AWSCredentialsProvider}.
*/
public class AWSRequestSigningApacheInterceptor implements HttpRequestInterceptor {
/**
* The service that we're connecting to. Technically not necessary.
* Could be used by a future Signer, though.
*/
private final String service;
/**
* The particular signer implementation.
*/
private final Signer signer;
/**
* The source of AWS credentials for signing.
*/
private final AWSCredentialsProvider awsCredentialsProvider;
/**
*
* @param service service that we're connecting to
* @param signer particular signer implementation
* @param awsCredentialsProvider source of AWS credentials for signing
*/
public AWSRequestSigningApacheInterceptor(final String service,
final Signer signer,
final AWSCredentialsProvider awsCredentialsProvider) {
this.service = service;
this.signer = signer;
this.awsCredentialsProvider = awsCredentialsProvider;
}
/**
* {@inheritDoc}
*/
@Override
public void process(final HttpRequest request, final HttpContext context)
throws HttpException, IOException {
URIBuilder uriBuilder;
try {
uriBuilder = new URIBuilder(request.getRequestLine().getUri());
} catch (URISyntaxException e) {
throw new IOException("Invalid URI" , e);
}
// Copy Apache HttpRequest to AWS DefaultRequest
DefaultRequest<?> signableRequest = new DefaultRequest<>(service);
HttpHost host = (HttpHost) context.getAttribute(HTTP_TARGET_HOST);
if (host != null) {
signableRequest.setEndpoint(URI.create(host.toURI()));
}
final HttpMethodName httpMethod =
HttpMethodName.fromValue(request.getRequestLine().getMethod());
signableRequest.setHttpMethod(httpMethod);
try {
signableRequest.setResourcePath(uriBuilder.build().getRawPath());
} catch (URISyntaxException e) {
throw new IOException("Invalid URI" , e);
}
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest httpEntityEnclosingRequest =
(HttpEntityEnclosingRequest) request;
if (httpEntityEnclosingRequest.getEntity() != null) {
signableRequest.setContent(httpEntityEnclosingRequest.getEntity().getContent());
}
}
signableRequest.setParameters(nvpToMapParams(uriBuilder.getQueryParams()));
signableRequest.setHeaders(headerArrayToMap(request.getAllHeaders()));
// Sign it
signer.sign(signableRequest, awsCredentialsProvider.getCredentials());
// Now copy everything back
request.setHeaders(mapToHeaderArray(signableRequest.getHeaders()));
if (request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest httpEntityEnclosingRequest =
(HttpEntityEnclosingRequest) request;
if (httpEntityEnclosingRequest.getEntity() != null) {
BasicHttpEntity basicHttpEntity = new BasicHttpEntity();
basicHttpEntity.setContent(signableRequest.getContent());
httpEntityEnclosingRequest.setEntity(basicHttpEntity);
}
}
}
/**
*
* @param params list of HTTP query params as NameValuePairs
* @return a multimap of HTTP query params
*/
private static Map<String, List<String>> nvpToMapParams(final List<NameValuePair> params) {
Map<String, List<String>> parameterMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (NameValuePair nvp : params) {
List<String> argsList =
parameterMap.computeIfAbsent(nvp.getName(), k -> new ArrayList<>());
argsList.add(nvp.getValue());
}
return parameterMap;
}
/**
* @param headers modeled Header objects
* @return a Map of header entries
*/
private static Map<String, String> headerArrayToMap(final Header[] headers) {
Map<String, String> headersMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (Header header : headers) {
if (!skipHeader(header)) {
headersMap.put(header.getName(), header.getValue());
}
}
return headersMap;
}
/**
* @param header header line to check
* @return true if the given header should be excluded when signing
*/
private static boolean skipHeader(final Header header) {
return ("content-length".equalsIgnoreCase(header.getName())
&& "0".equals(header.getValue())) // Strip Content-Length: 0
|| "host".equalsIgnoreCase(header.getName()); // Host comes from endpoint
}
/**
* @param mapHeaders Map of header entries
* @return modeled Header objects
*/
private static Header[] mapToHeaderArray(final Map<String, String> mapHeaders) {
Header[] headers = new Header[mapHeaders.size()];
int i = 0;
for (Map.Entry<String, String> headerEntry : mapHeaders.entrySet()) {
headers[i++] = new BasicHeader(headerEntry.getKey(), headerEntry.getValue());
}
return headers;
}
}
/*
* Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWS4UnsignedPayloadSigner;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.http.AWSRequestSigningApacheInterceptor;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Arrays;
import com.amazonaws.util.SdkHttpUtils;
import com.amazonaws.SignableRequest;
import com.amazonaws.auth.internal.AWS4SignerRequestParams;
import com.amazonaws.SignableRequest;
import com.amazonaws.auth.AWS4UnsignedPayloadSigner;
import com.amazonaws.auth.AWSCredentials;
import java.util.Map;
class ChaosSearchV4Signer extends AWS4UnsignedPayloadSigner {
private static final List<String> excludes = Arrays.asList("accept-encoding", "content-length", "transfer-encoding");
public ChaosSearchV4Signer() {
this.serviceName = "s3";
}
@Override public void setServiceName(String name) { }
@Override
public void sign(SignableRequest<?> request, AWSCredentials credentials) {
final Map<String,String> headers = request.getHeaders();
if (headers.containsKey("Content-Type") && headers.get("Content-Type").equals("application/json")) {
headers.put("Content-Type", "application/x-ndjson");
}
super.sign(request, credentials);
}
@Override
protected boolean shouldExcludeHeaderFromSigning(String header) {
return super.shouldExcludeHeaderFromSigning(header) || excludes.contains(header.toLowerCase());
}
}
class Sample {
static final String AWS_REGION = "us-east-1";
static final AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain();
public static void main(String[] args) throws IOException {
Sample sampleClass = new Sample();
sampleClass.makeGetRequest();
sampleClass.makePostRequest();
}
private void makeGetRequest() throws IOException {
HttpGet httpGet = new HttpGet("http://targethost/homepage");
logRequest("", httpGet);
}
private void makePostRequest() throws IOException {
HttpPost httpPost = new HttpPost("http://targethost/login");
List<NameValuePair> nvps = new ArrayList<>();
nvps.add(new BasicNameValuePair("username", "vip"));
nvps.add(new BasicNameValuePair("password", "secret"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
logRequest("", httpPost);
}
void logRequest(String serviceName, HttpUriRequest request) throws IOException {
System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "DEBUG");
CloseableHttpClient httpClient = signingClientForServiceName(serviceName);
try (CloseableHttpResponse response = httpClient.execute(request)) {
String inputLine ;
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
try {
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
CloseableHttpClient signingClientForServiceName(String serviceName) {
AWS4Signer signer = new ChaosSearchV4Signer();
signer.setServiceName(serviceName);
signer.setRegionName(AWS_REGION);
HttpRequestInterceptor interceptor = new AWSRequestSigningApacheInterceptor(serviceName, signer, credentialsProvider);
return HttpClients.custom()
.addInterceptorLast(interceptor)
.build();
}
HttpEntity stringEntity(final String body) throws UnsupportedEncodingException {
ByteArrayEntity httpEntity = new ByteArrayEntity(body.getBytes(StandardCharsets.UTF_8.name()));
return httpEntity;
}
}
Updated about 1 year ago