Selling partner Aws Sign4 wrong calcualation for vendor - amazon-web-services

I am using the API method "Directly making calls to Selling partner APIs".
I followed all the steps correctly:
Request a Login with Amazon access token - This API is working successfully & Getting access token.
Construct a Selling Partner API URI - After that, I took access_token and pass into options header request- 'x-amz-access-token'.
Add headers to the URI
Create and sign your request
After calling API https://sellingpartnerapi-eu.amazon.com/vendor/orders/v1/purchaseOrders
I am getting a signature response with error-
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method.
My code:-
let options = {
service: 'execute-api',
region:'eu-west-1',
method: 'GET',
url: 'https://sellingpartnerapi-eu.amazon.com/vendor/orders/v1/purchaseOrders/?includeDetails=true&createdBefore=2020-04-20T14:00:00-08:00&createdAfter=2020-04-14T00:00:00-08:00',
headers: {
'Content-Type': 'application/json',
'host':'sellingpartnerapi-eu.amazon.com',
'x-amz-access-token':access_token,
'x-amz-date': '20200604T061745Z',
'user-agent':'My App(Language=Node.js;Platform=Windows/10)'
}
}
let signedRequest = aws4.sign(options,
{
secretAccessKey: secretAccessKey,
accessKeyId: accessKeyId,
})
console.dir("signedRequest");
console.dir(signedRequest);
delete signedRequest.headers['Host']
delete signedRequest.headers['Content-Length']
request(awsres, function(err, res, body) {
console.dir("err");
console.dir(err);
console.dir("res");
console.dir(res.body);
});

I would imagine the signature is calculated the same way it is calculated in other AWS services.
Signature Version 4 signing process docs.
#aws-sdk/signature-v4-node -- official AWS SDK v3 signature package, but v3 is very much in beta. But I imagine they have figured out the signature package, as it wouldn't be possible to interact with the API without it.
aws-signature-v4 NodeJS package

Related

Dart Signature V4 client Error: The request signature we calculated does not match the signature you provided

I am using the following code to connect AWS REST API using IAM authentication. It's working fine on Google Chrome but giving errors in Firefox.
import 'package:aws_signature_v4/aws_signature_v4.dart';
const signer = AWSSigV4Signer();
final scope = AWSCredentialScope(
region: 'ap-south-1',
service: AWSService.apiGatewayManagementApi,
);
final request = AWSHttpRequest(
method: AWSHttpMethod.post,
uri: Uri.https('<URL>', 'PATH'),
headers: const {
AWSHeaders.contentType: 'application/json;charset=utf-8',
},
body: json.encode(payload).codeUnits,
);
// Sign and send the HTTP request
final signedRequest = await signer.sign(
request,
credentialScope: scope,
);
final resp = await signedRequest.send();
Error:
{"message":"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 String for this request should have been
'POST
<PATH>
content-type:application/json;charset=utf-8
host: <URL>
x-amz-content-sha256: <Key>
x-amz-date:20221017T065918Z
x-amz-user-agent:aws-sigv4-dart/0.2.2
content-type;host;x-amz-content-sha256;x-amz-date;x-amz-user-agent
<Key-1>
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20221017T065918Z
20221017/ap-south-1/execute-api/aws4_request
<Key-2>
"
}
I am using docs from https://docs.amplify.aws/lib/project-setup/escape-hatch/q/platform/flutter/
I seen couple of question on similar issue with no answers.
Appreciate any help on this.

Executing AWS Signv4 HTTP API from Javascript returns 403 error

I'm developing a Javascript (browser) client for HTTP API's in AWS API Gateway.The API's use an IAM authorizer. In my Javascript App I log in through a Cognito Identity Pool (developer identity). Next I convert the OpenID token into an access key id, secret access key and session token using AWS.CognitoIdentityCredentials.
I then want to use these credentials to make the API call, using the code below. I see the call being executed, but I get a HTTP/403 error back. The reply does not contain any further indication of the cause. I'd appreciate all help to understand what is going wrong. When disabling the IAM authorizer, the HTTP API works nicely.
I also tried the JWT authorizer, passing the OpenID token received from the Cognito Identity Pool (using http://cognito-identity.amazon.com as provider). When doing so I get the error: Bearer scope="" error="invalid_token" error_description="unable to decode "n" from RSA public key" in the www-authenticate response header.
Thanks a lot.
// Credentials will be available when this function is called.
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
let test_url = 'https://xxxxxxx.execute-api.eu-central-1.amazonaws.com/yyyyyy';
var httpRequest = new AWS.HttpRequest("https://" + test_url, "eu-central-1");
httpRequest.method = "GET";
AWS.config.credentials = {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
sessionToken: sessionToken
}
var v4signer = new AWS.Signers.V4(httpRequest, "execute-api");
v4signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());
fetch(httpRequest.endpoint.href , {
method: httpRequest.method,
headers: httpRequest.headers,
//body: httpRequest.body
}).then(function (response) {
if (!response.ok) {
$('body').html("ERROR: " + JSON.stringify(response.blob()));
return;
}
$('body').html("SUCCESS: " + JSON.stringify(response.blob()));
});
After some debugging and searching the web, I found the solution. Generating a correct signature seems to require a 'host' header:
httpRequest.headers.host = 'xxxxxxx.execute-api.eu-central-1.amazonaws.com'
After adding this host header the API call succeeds.

Password protect s3 bucket with lambda function in aws

I added website authentication for s3 bucket using lambda function and then connect the lambda function with the CloudFront by using behavior settings in distribution settings and it worked fine and added authentication(means htaccess authentication in simple servers). Now I want to change the password for my website authentication. For that, I updated the password and published the new version of the lambda function and then in the distribution settings; I created a new invalidation to clear cache. But it didn't work, and website authentication password didn't change. Below is my lambda function code to add authentication.
'use strict';
exports.handler = (event, context, callback) => {
// Get request and request headers
const request = event.Records[0].cf.request;
const headers = request.headers;
// Configure authentication
const authUser = 'user';
const authPass = 'pass';
// Construct the Basic Auth string
const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');
// Require Basic authentication
if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
const body = 'Unauthorized';
const response = {
status: '401',
statusDescription: 'Unauthorized',
body: body,
headers: {
'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
},
};
callback(null, response);
}
// Continue request processing if authentication passed
callback(null, request);
};
Can anyone please help me to solve the problem.
Thanks in advance.
On Lambda function view, After you save your changes (using Firefox could be a safer option, see below if you wonder why)
you will see a menu item under Configuration - > Designer -> CloudFront. You will see following screens.
After you deploy :
You can publish your change to CloudFront distribution. Once you publish this, it will automatically start deploying CF distribution which you can view on CF menu.
Also i would prefer using "Viewer Request" as a CloudFront trigger event, not sure which one you are using as this should avoid Cloudfront caching. On top of this Chrome sometimes fails to save changes on Lambda. There should be a bug on aws console. Try Firefox just to be safe when you are editing lambda functions.

uploading an image to AWS using react-native-aws-signature

hai i am try to upload an image to Amazon-s3 using react-native-aws-signature, here is my sample code i am attaching
var AWSSignature = require('react-native-aws-signature');
var awsSignature = new AWSSignature();
var source1 = {uri: response.uri, isStatic: true}; // this is uris which got from image picker
console.log("source:"+JSON.stringify(source1));
var credentials = {
SecretKey: ‘security-key’,
AccessKeyId: ‘AccesskeyId’,
Bucket:’Bucket_name’
};
var options = {
path: '/?Param2=value2&Param1=value1',
method: 'POST',
service: 'service',
headers: {
'X-Amz-Date': '20150209T123600Z',
'host': 'xxxxx.aws.amazon.com'
},
region: ‘us-east-1,
body: response.uri,
credentials
};
awsSignature.setParams(options);
var signature = awsSignature.getSignature();
var authorization = awsSignature.getAuthorizationHeader();
here i am declaring the source1 in that response.uri is passing in body which is coming from image picker,Can any one give suggestions that is there any wrong in my code, if there please tell me that how to resolve it,Any help much appreciated
awsSignature.getAuthorizationHeader(); will return the authorization header when given the correct parameters, and that's all it does.Just a step in the whole process of making a signed call to AWS API.
When sending POST request to S3, here is a link to the official documentation that you should read. S3 Documentation
It seems you need to send in the image as a form parameter.
You can also leverage the new AWS Amplify library on the official AWS repo here: https://github.com/aws/aws-amplify
This has a storage module for signing requests to S3: https://github.com/aws/aws-amplify/blob/master/media/storage_guide.md
For React Native you'll need to install that:
npm install aws-amplify-react-native
If you're using Cognito User Pool credentials you'll need to link the native bridge as outlined here: https://github.com/aws/aws-amplify/blob/master/media/quick_start.md#react-native-development

AWS IOT - Credential should be scoped to correct service

I am trying to access a simple AWS IOT REST service but I have not been able to do so successfully yet. Here is what I did.
I created an iam user in my aws and downloaded the access key and secret key
Logged into AWS IOT with that user and created a "thing"
From the thing's property I found the REST URL for the shadow
Used Postman with the new "aws signature" feature and provided it with the access key, secret key, region (us-east-1) and service name (iot)
Tried to "GET" the endpoint and this is what I got -
{
"message": "Credential should be scoped to correct service. ",
"traceId": "be056198-d202-455f-ab85-805defd1260d"
}
I thought there is something wrong with postman so I tried using aws-sdk-sample example of connecting to S3 and changed it to connect to the IOT URL.
Here is my program snippet (Java)
String awsAccessKey = "fasfasfasdfsdafs";
String awsSecretKey = "asdfasdfasfasdfasdfasdf/asdfsdafsd/fsdafasdf";
URL endpointUrl = null;
String regionName = "us-east-1";
try {
endpointUrl = new URL("https://dasfsdfasdf.iot.us-east-1.amazonaws.com/things/SOMETHING/shadow");
}catch (Exception e){
e.printStackTrace();
}
Map<String, String> headers = new HashMap<String, String>();
headers.put("x-amz-content-sha256", AWSSignerBase.EMPTY_BODY_SHA256);
AWSSignerForAuthorizationHeader signer = new AWSSignerForAuthorizationHeader(
endpointUrl, "GET", "iot", regionName);
String authorization = signer.computeSignature(headers,
null, // no query parameters
AWSSignerBase.EMPTY_BODY_SHA256,
awsAccessKey,
awsSecretKey);
// place the computed signature into a formatted 'Authorization' header
// and call S3
headers.put("Authorization", authorization);
String response = HttpUtils.invokeHttpRequest(endpointUrl, "GET", headers, null);
System.out.println("--------- Response content ---------");
System.out.println(response);
System.out.println("------------------------------------");
This gives me the same error -
--------- Request headers ---------
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: AWS4-HMAC-SHA256 Credential=fasfasfasdfsdafs/20160212/us-east-1/iot/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=3b2194051a8dde8fe617219c78c2a79b77ec92338028e9e917a74e8307f4e914
x-amz-date: 20160212T182525Z
Host: dasfsdfasdf.iot.us-east-1.amazonaws.com
--------- Response content ---------
{"message":"Credential should be scoped to correct service. ","traceId":"cd3e0d96-82fa-4da5-a4e1-b736af6c5e34"}
------------------------------------
Can someone tell me what I am doing wrong please? AWS documentation does not have much information on this error. Please help
Sign your request with iotdata instead if iot
example:
AWSSignerForAuthorizationHeader signer = new AWSSignerForAuthorizationHeader(
endpointUrl, "GET", "iotdata", regionName);
In your 4th step, don't fill anything for Service Name. Postman will default the value with execute-api.
Hope this works!
Its basically due to Service name is not given correctly you can use service Name = 'iotdata' instead of iot.
If you user Key management then Service Name would be kms.
For EC2 Service Name would be ec2 etc.
Use the AWS IoT SDK for Node.js instead. Download the IoT Console generated private key and client cert as well as the CA Root cert from here. Start with the scripts in the examples directory.