Skip to content

Instantly share code, notes, and snippets.

@a-shevtsov
Created March 19, 2019 00:19
Show Gist options
  • Save a-shevtsov/bff675a1b03640ede6f7c02920e160a6 to your computer and use it in GitHub Desktop.
Save a-shevtsov/bff675a1b03640ede6f7c02920e160a6 to your computer and use it in GitHub Desktop.
Signing requests with AWS Sigv4 in JMeter
/**
* This example has been tested against API Gateway
* The following HTTP Headers must be set (in HTTP Header Manager)
* Host: <hostname>
* Content-Type: application/json
* x-amz-date: ${amzDate}
* Authorization: ${amzAuth}
*/
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
final static char[] hexArray = "0123456789abcdef".toCharArray();
String getAmazonDate(LocalDateTime dt) {
String amzDate = dt.getYear().toString();
amzDate += (dt.getMonthValue() < 10) ? "0" + dt.getMonthValue() : dt.getMonthValue();
amzDate += (dt.getDayOfMonth() < 10) ? "0" + dt.getDayOfMonth() : dt.getDayOfMonth();
amzDate += "T";
amzDate += (dt.getHour() < 10) ? "0" + dt.getHour() : dt.getHour();
amzDate += (dt.getMinute() < 10) ? "0" + dt.getMinute() : dt.getMinute();
amzDate += (dt.getSecond() < 10) ? "0" + dt.getSecond() : dt.getSecond();
amzDate += "Z";
return amzDate;
}
byte[] HmacSHA256(String data, byte[] key) {
String algorithm = "HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF-8"));
}
byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) {
byte[] kSecret = ("AWS4" + key).getBytes("UTF-8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
byte[] getSha256(String text) {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
return hash;
}
// Retrieve method
String method = sampler.getMethod();
log.info("Method: " + method);
// Retrieve body
String body = method.equalsIgnoreCase("POST") ? sampler.getArguments().getArgument(0).getValue() : "";
log.info("Body: " + body);
// Retrieve URL from HTTP Request
URL url = sampler.getUrl();
String host = url.getHost();
log.info("Host: " + host);
String canonicalUri = url.getPath();
log.info("Path: " + canonicalUri);
String apiKey = "..access_key..";
String secretKey = "..secret_key..";
String region = "..region.."; # us-west-2 / us-east-1 / ...
String serviceName = "execute-api";
String canonicalQuerystring = "";
LocalDateTime currentTime = LocalDateTime.now(ZoneOffset.UTC);
String amzDate = getAmazonDate(currentTime);
String datestamp = amzDate.substring(0, 8);
String canonicalHeaders = "content-type:application/json\n" + "host:" + host + "\n" + "x-amz-date:" + amzDate + "\n";
String signedHeaders = "content-type;host;x-amz-date";
String payloadHash = bytesToHex(getSha256(body));
String canonicalRequest = method + "\n" + canonicalUri + "\n" + canonicalQuerystring + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + payloadHash;
log.info("Canonical request: " + canonicalRequest);
String algorithm = "AWS4-HMAC-SHA256";
String credentialScope = datestamp + "/" + region + "/" + serviceName + "/aws4_request";
String stringToSign = algorithm + "\n" + amzDate + "\n" + credentialScope + "\n" + bytesToHex(getSha256(canonicalRequest));
log.info("String to sign: " + stringToSign);
byte[] signingKey = getSignatureKey(secretKey, datestamp, region, serviceName);
String signature = bytesToHex(HmacSHA256(stringToSign, signingKey));
String amzAuth = "AWS4-HMAC-SHA256 Credential=" + apiKey + "/" + credentialScope + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature;
log.info("Authorization: " + amzAuth);
vars.put("amzDate", amzDate);
vars.put("amzAuth", amzAuth);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment