Skip to content

Commit

Permalink
Added JavaDoc and did some refactoring. Version 1.4.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Sandro committed Nov 16, 2018
1 parent d898e65 commit c012ee5
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 22 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>aws-v4-signer-java</artifactId>
<version>1.4.3-SNAPSHOT</version>
<version>1.4.4-SNAPSHOT</version>

<packaging>jar</packaging>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package uk.co.lucasweb.aws.v4.signer;

/**
* An authorization header string represented as its individual values.
* Created by sandro on 11/12/18
*/
public class Authorization {
Expand Down
35 changes: 24 additions & 11 deletions src/main/java/uk/co/lucasweb/aws/v4/signer/CanonicalRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class CanonicalRequest {
private static final String S3_SERVICE = "s3";
private static final char QUERY_PARAMETER_SEPARATOR = '&';
private static final char QUERY_PARAMETER_VALUE_SEPARATOR = '=';
private static final String X_AMZ_ALGORITHM = "X-Amz-Algorithm";
private static final String X_AMZ_CREDENTIAL = "X-Amz-Credential";
private static final String X_AMZ_DATE = "X-Amz-Date";
private static final String X_AMZ_EXPIRES = "X-Amz-Expires";
private static final String X_AMZ_SIGNED_HEADERS = "X-Amz-SignedHeaders";

private final String service;
private HttpRequest httpRequest;
Expand Down Expand Up @@ -166,24 +171,32 @@ private static List<Parameter> extractQueryParameters(String rawQuery) {
return results;
}

void addPreSignedUrlQueryParameters(String algorithm, String credentials, String date) {
addQueryParameters(algorithm, credentials, date, getHeaders().getNames());
void addQueryParametersForPreSignedUrl(String algorithm, String credentials, String date, int expiresInSeconds) {
addPreSignedUrlParamsToQueryParameters(algorithm, credentials, date, expiresInSeconds);

String query = buildQueryParametersString();

httpRequest = new HttpRequest(httpRequest.getMethod(), httpRequest.getPath() + query);
}

private void addQueryParameters(String algorithm, String credentials, String date, String signedHeaders) {
queryParameters.add(new Parameter("X-Amz-Algorithm", algorithm));
queryParameters.add(new Parameter("X-Amz-Credential", credentials));
queryParameters.add(new Parameter("X-Amz-Date", date));
queryParameters.add(new Parameter("X-Amz-SignedHeaders", signedHeaders));
private void addPreSignedUrlParamsToQueryParameters(String algorithm, String credentials, String date, int expiresInSeconds) {
queryParameters.add(new Parameter(X_AMZ_ALGORITHM, algorithm));
queryParameters.add(new Parameter(X_AMZ_CREDENTIAL, credentials));
queryParameters.add(new Parameter(X_AMZ_DATE, date));
queryParameters.add(new Parameter(X_AMZ_EXPIRES, String.valueOf(expiresInSeconds)));
queryParameters.add(new Parameter(X_AMZ_SIGNED_HEADERS, headers.getNames()));
queryParameters.sort(Comparator.comparing(parameter -> parameter.name));
}

private String buildQueryParametersString() {
StringBuffer sb = new StringBuffer();
sb.append('?');
queryParameters.forEach(p -> sb.append(p.name).append('=').append(p.value).append('&'));
String query = sb.toString();
query = query.substring(0, query.length() - 1);
queryParameters.forEach(p -> sb.append(p.name).append(QUERY_PARAMETER_VALUE_SEPARATOR).append(p.value).append(QUERY_PARAMETER_SEPARATOR));
return removeLastChar(sb.toString());
}

httpRequest = new HttpRequest(httpRequest.getMethod(), httpRequest.getPath() + query);
private String removeLastChar(String string) {
return string.substring(0, string.length() - 1);
}

private static final class Parameter {
Expand Down
65 changes: 59 additions & 6 deletions src/main/java/uk/co/lucasweb/aws/v4/signer/Signer.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,23 @@ String getStringToSign() {
return buildStringToSign(date, scope.get(), hashedCanonicalRequest);
}

/**
* Returns the calculated signature represented as Authorization header value.<br>
* e.g. AWS4-HMAC-SHA256 Credential="AccessKey"/20130524/us-east-1/s3/aws4_request,
* SignedHeaders=host;range;x-amz-content-sha256;x-amz-date,Signature="Signature"
* @return signature
*/
public String getSignature() {
String signature = buildSignature(awsCredentials.getSecretKey(), scope, getStringToSign());
return buildAuthHeader(getCredential(awsCredentials.getAccessKey(), scope.get()), request.getHeaders().getNames(), signature);
}

public Authorization getSignatureValues() {
/**
* Returns the calculated signature represented as {@link Authorization} object. In this way the
* calculated values can be retrieved individually.
* @return signature as {@link Authorization}
*/
public Authorization getSignatureValuesSeparately() {
String signature = buildSignature(awsCredentials.getSecretKey(), scope, getStringToSign());
String credential = getCredential(awsCredentials.getAccessKey(), scope.get());
return new Authorization(ALGORITHM, credential, date, request.getHeaders().getNames(), signature);
Expand Down Expand Up @@ -111,11 +122,13 @@ private static String buildSignature(String secretKey, CredentialScope scope, St
public static class Builder {

private static final String DEFAULT_REGION = "us-east-1";
private static final int DEFAULT_EXPIRATION = 86400; // 24hrs
private static final String S3 = "s3";
private static final String GLACIER = "glacier";

private AwsCredentials awsCredentials;
private String region = DEFAULT_REGION;
private int expiresIn = DEFAULT_EXPIRATION;
private List<Header> headersList = new ArrayList<>();

public Builder awsCredentials(AwsCredentials awsCredentials) {
Expand All @@ -128,6 +141,17 @@ public Builder region(String region) {
return this;
}

/**
* Sets the expiration time of a pre-signed Url.
* If not set, the default value (86400 seconds) will be used.
* @param expiresInSeconds Expiration time in seconds.
* @return {@link Builder}
*/
public Builder expires(int expiresInSeconds) {
this.expiresIn = expiresInSeconds;
return this;
}

public Builder header(String name, String value) {
headersList.add(new Header(name, value));
return this;
Expand All @@ -143,6 +167,13 @@ public Builder headers(Header... headers) {
return this;
}

/**
* Builds a generic {@link Signer} for signing various kinds of requests.
* @param request The http request.
* @param service String representation of the service used. e.g. "s3"
* @param contentSha256 A Sha256 encoded hash of the payload.
* @return {@link Signer}
*/
public Signer build(HttpRequest request, String service, String contentSha256) {
CanonicalHeaders canonicalHeaders = getCanonicalHeaders();
String date = canonicalHeaders.getFirstValue(X_AMZ_DATE)
Expand All @@ -154,22 +185,44 @@ public Signer build(HttpRequest request, String service, String contentSha256) {
return new Signer(canonicalRequest, awsCredentials, date, scope);
}

/**
* Builds a generic {@link Signer} for signing S3 requests.
* @param request The http request.
* @param contentSha256 A Sha256 encoded hash of the payload.
* @return {@link Signer}
*/
public Signer buildS3(HttpRequest request, String contentSha256) {
return build(request, S3, contentSha256);
}

public Signer buildS3PreSignedUrl(HttpRequest request, String date) {
/**
* Builds a {@link Signer} for signing a pre-signed Url. Note: The essential query parameters like
* X-Amz-Algorithm, X-Amz-Credential etc. should not be explicitly set in the Uri of the {@link HttpRequest},
* they are added automatically! A pre-signed request will use an unsigned payload as content hash.
* @param request The http request.
* @param xAmzDate Date represented as ISO8201 string.
* @return {@link Signer}
*/
public Signer buildS3PreSignedUrl(HttpRequest request, String xAmzDate) {
String service = S3;
String dateWithoutTimestamp = formatDateWithoutTimestamp(date);
AwsCredentials awsCredentials = getAwsCredentials();

String dateWithoutTimestamp = formatDateWithoutTimestamp(xAmzDate);
CredentialScope scope = new CredentialScope(dateWithoutTimestamp, service, region);
AwsCredentials awsCredentials = getAwsCredentials();
String credential = getCredential(awsCredentials.getAccessKey(), scope.get());

CanonicalRequest canonicalRequest = new CanonicalRequest(service, request, getCanonicalHeaders(), UNSIGNED_PAYLOAD);
canonicalRequest.addPreSignedUrlQueryParameters(ALGORITHM, getCredential(awsCredentials.getAccessKey(), scope.get()), date);
canonicalRequest.addQueryParametersForPreSignedUrl(ALGORITHM, credential, xAmzDate, expiresIn);

return new Signer(canonicalRequest, awsCredentials, date, scope);
return new Signer(canonicalRequest, awsCredentials, xAmzDate, scope);
}

/**
* Builds a generic {@link Signer} for signing Glacier requests.
* @param request The http request.
* @param contentSha256 A Sha256 encoded hash of the payload.
* @return {@link Signer}
*/
public Signer buildGlacier(HttpRequest request, String contentSha256) {
return build(request, GLACIER, contentSha256);
}
Expand Down
6 changes: 2 additions & 4 deletions src/test/java/uk/co/lucasweb/aws/v4/signer/SignerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
package uk.co.lucasweb.aws.v4.signer;

import org.junit.Ignore;
import org.junit.Test;
import uk.co.lucasweb.aws.v4.signer.credentials.AwsCredentials;

Expand Down Expand Up @@ -99,20 +98,19 @@ public void shouldSignStreamingRequest() throws Exception {
assertThat(signature).isEqualTo(expectedSignature);
}

@Ignore
@Test
public void shouldSignPreSignedRequestUrl() throws Exception {
String imageFileName = "test.txt";

URI uri = new URI("https://examplebucket.s3.amazonaws.com/" + imageFileName + "?X-Amz-Expires=86400");
URI uri = new URI("https://examplebucket.s3.amazonaws.com/" + imageFileName);
HttpRequest request = new HttpRequest("GET", uri);
String xAmzDate = "20130524T000000Z";
Authorization a = Signer.builder()
.awsCredentials(new AwsCredentials("AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"))
.header("Host", "examplebucket.s3.amazonaws.com")
.region("us-east-1")
.buildS3PreSignedUrl(request, xAmzDate)
.getSignatureValues();
.getSignatureValuesSeparately();

assertThat(a.getSignature()).isEqualTo("aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404");
}
Expand Down

0 comments on commit c012ee5

Please sign in to comment.