Here is my code in the JSR223 PreProcessor.
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.security.InvalidKeyException
import java.security.MessageDigest
import groovy.json.JsonSlurper
import java.text.SimpleDateFormat
static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
Example parameter values to the function getSignatureKey are (these I am passing to the Parameters section of the JSR223 PreProcessor as variables)
key = eC6hEyRSTXMzsG6+juOObz8LbXb36iEYW7PPN1MJ
dateStamp = 20190123T083434Z
regionName = us-west-2
serviceName = test-mlp-us-west-2-4023179c-7708-4c5e-a831-28259b8a8872.s3.us-west-2.amazonaws.com
This code is not working and not generating the AWS signature.
Here is the sample Signature value I need to get
Signature=2a6092ec4ff49dc9j3b92d436635a57f312753kcc9f553ce1718b9b1594c4362
1.What is wrong with this code?
2.How can I assign the AWS signature to a variable and use in the JMeter?
If "This code is not working" the first thing you should do is to look into jmeter.log file - in case of Groovy script failure it will contain information regarding what exactly failed and why and some hints to fix.
I also think you should generate the signature basing on request details (URL, parameters, headers, etc.)
StringToSign =
Algorithm + \n +
RequestDateTime + \n +
CredentialScope + \n +
HashedCanonicalRequest
See Create a String to Sign for Signature Version 4
The whole process with examples is described in the How to Handle Dynamic AWS SigV4 in JMeter for API Testing and the test plan you can use as the reference is available in the GitHub repo.
Related
I'm getting "TypeError: Cannot read property 'sigBytes' of undefined" error when running a postman collection with a cryptojs pre-request script. The pre-request script computes a hmac-sha256 signature which is also part of parameters of the main API to be called.
Below is my script:
let mobile = pm.environment.get('mobileNumber');
let value = pm.environment.get('value');
let merchantId = pm.environment.get('merchantId');
let referenceNumber = pm.environment.get('referenceNumber');
let authCode = pm.environment.get('authCode');
let secretKey = pm.environment.get('secretKey');
let string = mobile + value + merchantId + referenceNumber + authCode;
pm.environment.set('string', string);
let hmac = CryptoJS.HmacSHA256(string, secretKey);
pm.environment.set('hmac', hmac);
signature = "hmac256-" + hmac;
pm.environment.set('signature', signature);
I already tried encoding the string and secretKey to UTF-8, base64stringify, JSON stringify but I'm getting errors still.
Here are sample values from each of the variables:
mobile - +639012345678
value - 100
merchantId - TEST_MERCHANT1
referenceNumber - TEST_MERCHANT1-000001
authCode - 000001
secretKey - a2c36909-c9cc-4ed3-9423-ec170e1eb6c2
Looks like at least one of your environment variables isn't defined.
The error message is due to a bug in CryptoJS: https://github.com/brix/crypto-js/issues/85
I am new to AWSLex. I was trying to fetch the SlotType information through ModelBuilding GetSlotType API.
The request URL: GET /slottypes/name/versions/version HTTP/1.1
To fetch the latest version as per document is Pattern: \$LATEST|[0-9]+
Through Postman I am able to execute with version number.But while fetching the latest version $LATEST, the URL I used is
https://models.lex.us-east-1.amazonaws.com/slottypes/serviceType/versions/%24LATEST
which worked perfectly through Postman.
The same url when I had used to create the signature didn't work. I get following error
"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
The canonical request what I had generated is below
GET
/slottypes/serviceType/versions/%24LATEST
content-type:application/json
host:models.lex.us-east-1.amazonaws.com
x-amz-date:20180809T052553Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Any help on how to fix the issue is highly appreciated.
String payloadHash = CommonUtil.hexEncode(sha256Hash(payload));
ZonedDateTime utcNow = Instant.now().atZone(ZoneOffset.UTC);// Date
for headers and the credential string
String amzDate =
utcNow.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
String dateStamp =
utcNow.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String canonicalHeaders = String.format("content-type:%s\nhost:%s\nx-
amz-date:%s\n", contentType, host, amzDate);
String canonicalRequest = String.format("%s\n%s\n%s\n%s\n%s\n%s",
method, canonicalUri, canonicalQueryString, canonicalHeaders,
signedHeaders, payloadHash);
String credentialScope = String.format("%s/%s/%s/aws4_request",
dateStamp, region, service);
String canonicalRequestHash =
CommonUtil.hexEncode(sha256Hash(canonicalRequest));
String stringToSign = String.format("%s\n%s\n%s\n%s", algorithm,
amzDate, credentialScope, canonicalRequestHash);
byte[] signatureKey = CommonUtil.getSignatureKey(secretKey,
dateStamp, region, service);
String signature = CommonUtil.hexEncode(CommonUtil.HmacSHA256(URLEncoder.encode(stringToSign,"utf-8"), signatureKey));
String authorizationHeader = String.format("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", algorithm, accessKey, credentialScope, signedHeaders, signature);
MultivaluedMap<String, String> headersMap = new MultivaluedHashMap<>();
headersMap.add("Content-Type", contentType);
headersMap.add("X-Amz-Date", amzDate);
headersMap.add("Authorization", authorizationHeader);
This is how I am generating the signature.The same code works fine with version as number. The issue lies when I encode the url with $LATEST as value and pass it.
String distributionDomain = "d21geuebylb7j1.cloudfront.net";
String privateKeyFilePath = "/Users/Desktop/rsa-private-key.der";
String s3ObjectKey = "small.mp4";
String policyResourcePath = "http://" + distributionDomain + "/" + s3ObjectKey;
System.out.println(privateKeyFilePath);
byte[] derPrivateKey = null;
I am trying to make signed URL for my cloudfront distribution but I am getting invalid key error. I am getting issue with my rsa-private-key.der file. I have made this file from pem file as mentioned in Cloudfront documentation.
Below is my error logs:
Exception in thread "main" org.jets3t.service.CloudFrontServiceException: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at org.jets3t.service.CloudFrontService.signUrlCanned(CloudFrontService.java:2148)
at test.SignedURL.main(SignedURL.java:74)
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:216)
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
at org.jets3t.service.security.EncryptionUtil.signWithRsaSha1(EncryptionUtil.java:526)
at org.jets3t.service.CloudFrontService.signUrlCanned(CloudFrontService.java:2133)
... 1 more
Caused by: java.security.InvalidKeyException: invalid key format
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:330)
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:356)
at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:315)
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:212)
... 4 more
I had same issue this solved my issue.
You can try this:
public enum CloudFrontUrlSigner
extends Enum<CloudFrontUrlSigner>
Utility class for generating pre-signed URLs for serving private CloudFront content. All dates must be in UTC. Use Calendar to set the timezone specifically before converting to a Date object, or else use DateUtils to turn a UTC date String into a Date object.
Protocol protocol = Protocol.http;
String distributionDomain = "d1b2c3a4g5h6.cloudfront.net";
File privateKeyFile = new File("/path/to/cfcurlCloud/rsa-private-key.pem");
String s3ObjectKey = "a/b/images.jpeg";
String keyPairId = "APKAJCEOKRHC3XIVU5NA";
Date dateLessThan = DateUtils.parseISO8601Date("2012-11-14T22:20:00.000Z");
Date dateGreaterThan = DateUtils.parseISO8601Date("2011-11-14T22:20:00.000Z");
String ipRange = "192.168.0.1/24";
String url1 = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(
protocol, distributionDomain, privateKeyFile,
s3ObjectKey, keyPairId, dateLessThan);
String url2 = CloudFrontUrlSigner.getSignedURLWithCustomPolicy(
protocol, distributionDomain, privateKeyFile,
s3ObjectKey, keyPairId, dateLessThan,
dateGreaterThan, ipRange);
here is the link of AWS Documentation: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html
I'm testing an application which is hosted on AWS infrastructure using JMeter tool wherein each request triggered needs to have a AWS signed header passed along with the request to validate the request at the IAM level in AWS. I have the access and secret key pertaining to the user role created in AWS console.
Is there any beanshell code available in JMeter which helps in generating AWS signature using the access and secret key for each request in JMeter?
The code is available on AWS docs website, see Deriving the Signing Key with Java for instance. Here is minimal listing just in case:
static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm="HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF8"));
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
Be aware that starting from JMeter version 3.1 it is recommended to use JSR223 Elements and Groovy language for scripting as it is more modern (supports all new Java SDK features), has a lot of "syntax sugar" on top of "normal" Java SDK and Groovy performance is much better comparing to Beanshell, JavaScript and other available options. See Apache Groovy - Why and How You Should Use It article for more details.
I am current working with Google Apps script and am attempting to write & sign an HTTP request to AWS CloudWatch.
On the Amazon API documentation here regarding how to create a signing key, they use pseudo to explain that the HMAC algorithm is to return binary format.
HMAC(key, data) represents an HMAC-SHA256 function
that returns output in binary format.
Google apps script offers a method to do such a hash,
Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,
data,
key);
but the return type is always a byte array.
Byte[]
How do I convert the Byte[] to the binary data AWS wants? Or is there a vanilla javascript function I can use in Google Apps Script to compute the hash?
Thanks
I am quite sure it is a bug that Utilities.computeHmacSignature take key as an ASCII. But there was no way to parse byte[] to ASCII correctly in GAS
And the library writer is too stupid too just provide function which take key as byte[]
So I use this instead : http://caligatio.github.com/jsSHA/
Just copy SHA.js and SHA-256.js then it work fine
PS. it waste my time for whole 2 days so I'm very annoying
The conversion from byte array to the binary data required should be simple:
kDate = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,
'20130618', 'AWS4' + kSecret);
kDate = Utilities.newBlob(kDate).getDataAsString();
kRegion = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,
'eu-west-1', kDate);
BUT you have to look onto this open issue in the bugtracker - there could be some issues in conversion.
maybe you could try to make a String.fromCharCode() loop and avoid negative numers:
kDateB = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,
'20130618', 'AWS4' + kSecret);
kDate = '';
for (var i=0; i<kDateB.length; i++)
kDate += String.fromCharCode(kDateB[i]<0?256+kDateB[i]:0+kDateB[i]);
kRegion = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,
'eu-west-1', kDate);