Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
.idea/
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
Expand Down Expand Up @@ -59,14 +60,13 @@ public class AWSRequestSigningApacheInterceptor implements HttpRequestIntercepto
private final AWSCredentialsProvider awsCredentialsProvider;

/**
*
* @param service service that we're connecting to
* @param signer particular signer implementation
* @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) {
final Signer signer,
final AWSCredentialsProvider awsCredentialsProvider) {
this.service = service;
this.signer = signer;
this.awsCredentialsProvider = awsCredentialsProvider;
Expand All @@ -82,7 +82,7 @@ public void process(final HttpRequest request, final HttpContext context)
try {
uriBuilder = new URIBuilder(request.getRequestLine().getUri());
} catch (URISyntaxException e) {
throw new IOException("Invalid URI" , e);
throw new IOException("Invalid URI", e);
}

// Copy Apache HttpRequest to AWS DefaultRequest
Expand All @@ -98,7 +98,7 @@ public void process(final HttpRequest request, final HttpContext context)
try {
signableRequest.setResourcePath(uriBuilder.build().getRawPath());
} catch (URISyntaxException e) {
throw new IOException("Invalid URI" , e);
throw new IOException("Invalid URI", e);
}

if (request instanceof HttpEntityEnclosingRequest) {
Expand All @@ -111,24 +111,34 @@ public void process(final HttpRequest request, final HttpContext context)
signableRequest.setParameters(nvpToMapParams(uriBuilder.getQueryParams()));
signableRequest.setHeaders(headerArrayToMap(request.getAllHeaders()));

SignableRequestContentChangeInterceptor<?> wrappedSignableRequest =
new SignableRequestContentChangeInterceptor<>(signableRequest);

// Sign it
signer.sign(signableRequest, awsCredentialsProvider.getCredentials());
signer.sign(wrappedSignableRequest, awsCredentialsProvider.getCredentials());

// Now copy everything back
request.setHeaders(mapToHeaderArray(signableRequest.getHeaders()));
if (request instanceof HttpEntityEnclosingRequest) {
// Replace http entity only if content got changed
if (wrappedSignableRequest.isContentChanged() &&
request instanceof HttpEntityEnclosingRequest) {
HttpEntityEnclosingRequest httpEntityEnclosingRequest =
(HttpEntityEnclosingRequest) request;
if (httpEntityEnclosingRequest.getEntity() != null) {
BasicHttpEntity basicHttpEntity = new BasicHttpEntity();
basicHttpEntity.setContent(signableRequest.getContent());
if (request.getFirstHeader(HttpHeaders.CONTENT_TYPE) != null) {
basicHttpEntity.setContentType(request.getFirstHeader(HttpHeaders.CONTENT_TYPE));
}
if (request.getFirstHeader(HttpHeaders.CONTENT_ENCODING) != null) {
basicHttpEntity.setContentEncoding(request.getFirstHeader(HttpHeaders.CONTENT_ENCODING));
}
httpEntityEnclosingRequest.setEntity(basicHttpEntity);
}
}
}

/**
*
* @param params list of HTTP query params as NameValuePairs
* @return a multimap of HTTP query params
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.amazonaws.http;

import com.amazonaws.ReadLimitInfo;
import com.amazonaws.SignableRequest;

import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.Map;

/**
* Wrapper for SignableRequest which intercepts if the request content is changed.
*
* @param <T>
*/
public class SignableRequestContentChangeInterceptor<T> implements SignableRequest<T> {
private final SignableRequest<T> original;
private boolean contentChanged = false;

public SignableRequestContentChangeInterceptor(final SignableRequest<T> original) {
this.original = original;
}

@Override
public void addHeader(final String name, final String value) {
original.addHeader(name, value);
}

@Override
public void addParameter(final String name, final String value) {
original.addParameter(name, value);
}

@Override
public void setContent(final InputStream inputStream) {
original.setContent(inputStream);
contentChanged = true;
}

@Override
public Map<String, String> getHeaders() {
return original.getHeaders();
}

@Override
public String getResourcePath() {
return original.getResourcePath();
}

@Override
public Map<String, List<String>> getParameters() {
return original.getParameters();
}

@Override
public URI getEndpoint() {
return original.getEndpoint();
}

@Override
public HttpMethodName getHttpMethod() {
return original.getHttpMethod();
}

@Override
public int getTimeOffset() {
return original.getTimeOffset();
}

@Override
public InputStream getContent() {
return original.getContent();
}

@Override
public InputStream getContentUnwrapped() {
return original.getContentUnwrapped();
}

@Override
public ReadLimitInfo getReadLimitInfo() {
return original.getReadLimitInfo();
}

@Override
public Object getOriginalRequestObject() {
return original.getOriginalRequestObject();
}

public boolean isContentChanged() {
return contentChanged;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,37 @@
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.AnonymousAWSCredentials;
import com.amazonaws.auth.Signer;
import com.amazonaws.util.IOUtils;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

public class AWSRequestSigningApacheInterceptorTest {

private static AWSRequestSigningApacheInterceptor createInterceptor() {
private static AWSRequestSigningApacheInterceptor createInterceptor(Signer signer) {
AWSCredentialsProvider anonymousCredentialsProvider =
new AWSStaticCredentialsProvider(new AnonymousAWSCredentials());
return new AWSRequestSigningApacheInterceptor("servicename",
new AddHeaderSigner("Signature", "wuzzle"),
signer,
anonymousCredentialsProvider);

}

@Test
Expand All @@ -55,7 +62,8 @@ public void testSimpleSigner() throws Exception {
HttpCoreContext context = new HttpCoreContext();
context.setTargetHost(HttpHost.create("localhost"));

createInterceptor().process(request, context);
createInterceptor(new AddHeaderSigner("Signature", "wuzzle"))
.process(request, context);

assertEquals("bar", request.getFirstHeader("foo").getValue());
assertEquals("wuzzle", request.getFirstHeader("Signature").getValue());
Expand All @@ -64,45 +72,104 @@ public void testSimpleSigner() throws Exception {

@Test(expected = IOException.class)
public void testBadRequest() throws Exception {

HttpRequest badRequest = new BasicHttpRequest("GET", "?#!@*%");
createInterceptor().process(badRequest, new BasicHttpContext());
createInterceptor(new AddHeaderSigner("Signature", "wuzzle"))
.process(badRequest, new BasicHttpContext());
}

private static class AddHeaderSigner implements Signer {
private final String name;
private final String value;
@Test
public void testHttpEntityIsCorrect() throws Exception {
HttpEntityEnclosingRequest request =
new BasicHttpEntityEnclosingRequest("GET", "/query?a=b");
BasicHttpEntity httpEntity = new BasicHttpEntity();
InputStream content = new ByteArrayInputStream(new byte[]{0, 1});
httpEntity.setContent(content);
httpEntity.setContentEncoding("gzip");
request.setEntity(httpEntity);

private AddHeaderSigner(String name, String value) {
this.name = name;
this.value = value;
}
HttpCoreContext context = new HttpCoreContext();
context.setTargetHost(HttpHost.create("localhost"));

createInterceptor(new AddHeaderSigner("Signature", "wuzzle"))
.process(request, context);

@Override
public void sign(SignableRequest<?> request, AWSCredentials credentials) {
request.addHeader(name, value);
request.addHeader("resourcePath", request.getResourcePath());
}
assertNotNull(request.getEntity());
assertNotNull(request.getEntity().getContentEncoding());
assertEquals("gzip", request.getEntity().getContentEncoding().getValue());
assertEquals(content, request.getEntity().getContent());
}

@Test
public void testReplaceContentSigner() throws Exception {
HttpEntityEnclosingRequest request =
new BasicHttpEntityEnclosingRequest("GET", "/query?a=b");
ByteArrayEntity byteArrayEntity = new ByteArrayEntity("I'm an entity".getBytes(),
ContentType.TEXT_PLAIN);
request.setEntity(byteArrayEntity);
request.addHeader("foo", "bar");
request.addHeader("content-length", "0");
request.addHeader(byteArrayEntity.getContentType());

HttpCoreContext context = new HttpCoreContext();
context.setTargetHost(HttpHost.create("localhost"));

createInterceptor(new ReplaceContentSigner("new content"))
.process(request, context);
assertNotNull(request.getEntity().getContentType());
assertEquals(ContentType.TEXT_PLAIN.toString(),
request.getEntity().getContentType().getValue());
assertArrayEquals("new content".getBytes(),
IOUtils.toByteArray(request.getEntity().getContent()));
}

@Test
public void testEncodedUriSigner() throws Exception {
HttpEntityEnclosingRequest request =
new BasicHttpEntityEnclosingRequest("GET", "/foo-2017-02-25%2Cfoo-2017-02-26/_search?a=b");
new BasicHttpEntityEnclosingRequest("GET",
"/foo-2017-02-25%2Cfoo-2017-02-26/_search?a=b");
request.setEntity(new StringEntity("I'm an entity"));
request.addHeader("foo", "bar");
request.addHeader("content-length", "0");

HttpCoreContext context = new HttpCoreContext();
context.setTargetHost(HttpHost.create("localhost"));

createInterceptor().process(request, context);
createInterceptor(new AddHeaderSigner("Signature", "wuzzle"))
.process(request, context);

assertEquals("bar", request.getFirstHeader("foo").getValue());
assertEquals("wuzzle", request.getFirstHeader("Signature").getValue());
assertNull(request.getFirstHeader("content-length"));
assertEquals("/foo-2017-02-25%2Cfoo-2017-02-26/_search", request.getFirstHeader("resourcePath").getValue());
assertEquals("/foo-2017-02-25%2Cfoo-2017-02-26/_search",
request.getFirstHeader("resourcePath").getValue());
}

private static class AddHeaderSigner implements Signer {
private final String name;
private final String value;

private AddHeaderSigner(String name, String value) {
this.name = name;
this.value = value;
}

@Override
public void sign(SignableRequest<?> request, AWSCredentials credentials) {
request.addHeader(name, value);
request.addHeader("resourcePath", request.getResourcePath());
}
}

private static class ReplaceContentSigner implements Signer {
private final String content;

public ReplaceContentSigner(final String content) {
this.content = content;
}

@Override
public void sign(SignableRequest<?> request, AWSCredentials credentials) {
request.setContent(new ByteArrayInputStream(content.getBytes()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.amazonaws.http;

import com.amazonaws.DefaultRequest;
import com.amazonaws.SignableRequest;
import org.junit.Assert;
import org.junit.Test;

import java.io.ByteArrayInputStream;

public class SignableRequestContentChangeInterceptorTest {
@Test
public void testContentChangeDetected() {
SignableRequest<?> signableRequest = new DefaultRequest<>("test-service");
signableRequest.setContent(new ByteArrayInputStream(new byte[]{0, 1}));
SignableRequestContentChangeInterceptor<?> wrapped =
new SignableRequestContentChangeInterceptor<>(signableRequest);
Assert.assertFalse(wrapped.isContentChanged());
wrapped.setContent(new ByteArrayInputStream(new byte[]{1, 2}));
Assert.assertTrue(wrapped.isContentChanged());
}
}