All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.fabric8.maven.docker.access.ecr.AwsSigner4 Maven / Gradle / Ivy
package io.fabric8.maven.docker.access.ecr;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import io.fabric8.maven.docker.access.AuthConfig;
import org.codehaus.plexus.util.StringUtils;
/**
* AwsSigner4 implementation that signs requests with the AWS4 signing protocol. Refer to the AWS docs for mor details.
*
* @author chas
* @since 2016-12-9
*/
class AwsSigner4 {
// a-f must be lower case
final private static char[] HEXITS = "0123456789abcdef".toCharArray();
private final String service;
private final String region;
/**
* A signer for a particular region and service.
*
* @param region The aws region.
* @param service The aws service.
*/
AwsSigner4(String region, String service) {
this.region = region;
this.service = service;
}
/**
* Sign a request. Add the headers that authenticate the request.
*
* @param request The request to sign.
* @param credentials The credentials to use when signing.
* @param signingTime The invocation time to use;
*/
void sign(HttpRequest request, AuthConfig credentials, Date signingTime) {
AwsSigner4Request sr = new AwsSigner4Request(region, service, request, signingTime);
if(!request.containsHeader("X-Amz-Date")) {
request.addHeader("X-Amz-Date", sr.getSigningDateTime());
}
request.addHeader("Authorization", task4(sr, credentials));
final String securityToken = credentials.getAuth();
if (StringUtils.isNotEmpty(securityToken)) {
request.addHeader("X-Amz-Security-Token", securityToken);
}
}
/**
* Task 1.
* Create a Canonical Request
*/
String task1(AwsSigner4Request sr) {
StringBuilder sb = new StringBuilder(sr.getMethod()).append('\n')
.append(sr.getUri().getRawPath()).append('\n')
.append(getCanonicalQuery(sr.getUri())).append('\n')
.append(sr.getCanonicalHeaders()).append('\n')
.append(sr.getSignedHeaders()).append('\n');
hexEncode(sb, sha256(sr.getBytes()));
return sb.toString();
}
/**
* Task 2.
* Create a String to Sign for Signature Version 4
*/
String task2(AwsSigner4Request sr) {
StringBuilder sb = new StringBuilder("AWS4-HMAC-SHA256\n")
.append(sr.getSigningDateTime()).append('\n')
.append(sr.getScope()).append('\n');
hexEncode(sb, sha256(task1(sr)));
return sb.toString();
}
/**
* Task 3.
* Calculate the Signature for AWS Signature Version 4
*/
final byte[] task3(AwsSigner4Request sr, AuthConfig credentials) {
return hmacSha256(getSigningKey(sr, credentials), task2(sr));
}
private static byte[] getSigningKey(AwsSigner4Request sr, AuthConfig credentials) {
byte[] kSecret = ("AWS4" + credentials.getPassword()).getBytes(StandardCharsets.UTF_8);
byte[] kDate = hmacSha256(kSecret, sr.getSigningDate());
byte[] kRegion = hmacSha256(kDate, sr.getRegion());
byte[] kService = hmacSha256(kRegion, sr.getService());
return hmacSha256(kService, "aws4_request");
}
/**
* Task 4.
* Add the Signing Information to the Request
*/
String task4(AwsSigner4Request sr, AuthConfig credentials) {
StringBuilder sb = new StringBuilder("AWS4-HMAC-SHA256 Credential=")
.append(credentials.getUsername() ).append( '/' ).append( sr.getScope() )
.append(", SignedHeaders=").append(sr.getSignedHeaders())
.append(", Signature=" );
hexEncode(sb, task3(sr, credentials));
return sb.toString();
}
private String getCanonicalQuery(URI uri) {
String query = uri.getQuery();
if(query == null || query.isEmpty()) {
return "";
}
List params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
Collections.sort(params, new Comparator() {
@Override
public int compare(NameValuePair l, NameValuePair r) {
return l.getName().compareToIgnoreCase(r.getName());
}
});
return URLEncodedUtils.format(params, StandardCharsets.UTF_8);
}
static void hexEncode(StringBuilder dst, byte[] src) {
for (byte aSrc : src) {
int v = aSrc & 0xFF;
dst.append(HEXITS[v >>> 4]);
dst.append(HEXITS[v & 0x0F]);
}
}
private static byte[] hmacSha256(byte[] key, String value) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(value.getBytes(StandardCharsets.UTF_8));
}
catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new UnsupportedOperationException(e.getMessage(), e);
}
}
private static byte[] sha256(String string) {
return sha256(string.getBytes(StandardCharsets.UTF_8));
}
private static byte[] sha256(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes);
return md.digest();
}
catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e.getMessage(), e);
}
}
}