Closed Mike-the-one closed 2 years ago
Here are the request header and body:
Request body:
{
"targetApplication":"Target Application",
"restrictedResources":[
{
"method":"GET",
"path":"[/orders/v0/orders]()",
"dataElements":[
"buyerInfo",
"shippingAddress"
]
}
]
}
And headers: (* are the values I replaced)
Accept = application/json
Authorization = AWS4-HMAC-SHA256 Credential=********************/20220204/us-east-1/execute-api/aws4_request, SignedHeaders=accept;content-type;host;user-agent;x-amz-access-token;x-amz-date;x-amz-security-token, Signature=ea0d96571eef2558959beb43c4c062877e073bb4a9f8ab80b2c2443fd8c34f2c
Content-Type = application/json
Host = sellingpartnerapi-na.amazon.com
User-Agent = Swagger-Codegen/1.1.0/java
x-amz-access-token = *************
X-Amz-Date = 20220204T113050Z
X-Amz-Security-Token = ************
Do they look right? The AppClient.java
is generated by swagger cli, AWSSigV4Signer.java
is from the latest one from repo https://github.com/amzn/selling-partner-api-models
AWS dependency version
compile group: 'com.amazonaws', name: 'aws-java-sdk-signer', version: '1.12.9'
compile group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.12.9'
This is the buildRequest
method from AppClient.java
(I added systemout):
/**
* Build an HTTP request with the given options.
*
* @param path The sub-path of the HTTP URL
* @param method The request method, one of "GET", "HEAD",
* "OPTIONS", "POST", "PUT", "PATCH" and "DELETE"
* @param queryParams The query parameters
* @param collectionQueryParams The collection query parameters
* @param body The request body object
* @param headerParams The header parameters
* @param formParams The form parameters
* @param authNames The authentications to apply
* @param progressRequestListener Progress request listener
* @return The HTTP request
* @throws ApiException If fail to serialize the request body object
*/
public Request buildRequest(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams,
Object body, Map<String, String> headerParams, Map<String, Object> formParams, String[] authNames,
ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
updateParamsForAuth(authNames, queryParams, headerParams);
final String url = buildUrl(path, queryParams, collectionQueryParams);
final Request.Builder reqBuilder = new Request.Builder().url(url);
processHeaderParams(headerParams, reqBuilder);
String contentType = (String) headerParams.get("Content-Type");
// ensuring a default content type
if (contentType == null) {
contentType = "application/json";
}
RequestBody reqBody;
if (!HttpMethod.permitsRequestBody(method)) {
reqBody = null;
} else if ("application/x-www-form-urlencoded".equals(contentType)) {
reqBody = buildRequestBodyFormEncoding(formParams);
} else if ("multipart/form-data".equals(contentType)) {
reqBody = buildRequestBodyMultipart(formParams);
} else if (body == null) {
if ("DELETE".equals(method)) {
// allow calling DELETE without sending a request body
reqBody = null;
} else {
// use an empty request body (for POST, PUT and PATCH)
reqBody = RequestBody.create(MediaType.parse(contentType), "");
}
} else {
reqBody = serialize(body, contentType);
}
Request request = null;
if (progressRequestListener != null && reqBody != null) {
ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, progressRequestListener);
request = reqBuilder.method(method, progressRequestBody).build();
} else {
request = reqBuilder.method(method, reqBody).build();
}
request = lwaAuthorizationSigner.sign(request);
request = awsSigV4Signer.sign(request);
Headers headers = request.headers();
Set<String> names = headers.names();
for (String n : names) {
System.out.println(n + " = " + headers.get(n));
}
return request;
}
Tried latest dependencies, same result.
compile group: 'com.amazonaws', name: 'aws-java-sdk-signer', version: '1.12.152'
compile group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.12.152'
I am able to call SellersAPI.getMarketplaceParticipations()
and OrdersAPI.getOrders()
, both of these are GET commands, so no request body, I wondering if I miss something that the signer does not include the body to sign?
@ShivikaK Do you mind take a look?
@ShivikaK
This is the response body (* are the values I replaced)
{
"errors": [
{
"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
/tokens/2021-03-01/restrictedDataToken
accept:application/json
content-type:application/json; charset=utf-8
host:sellingpartnerapi-na.amazon.com
user-agent:Swagger-Codegen/1.1.0/java
x-amz-access-token:**************
x-amz-date:20220204T123510Z
x-amz-security-token:********
accept;content-type;host;user-agent;x-amz-access-token;x-amz-date;x-amz-security-token
********(I replaced)'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20220204T123510Z
20220204/us-east-1/execute-api/aws4_request
0fa************************************8e2c'
",
"code": "InvalidSignature"
}
]
}
For anyone had the similar issue, the problem is how I generate the client code, especially this line
"useGzipFeature": true,
If turned on, the ApiClient.java
will have a line like this
httpClient.interceptors().add(new GzipRequestInterceptor());
That is the problem. The signature was added before the gzip header is added, then Amazon will calculate the signature with the gzip and of course it will not match!
Thanks to @rohitdobariya who spotted the issue!
I am able to call
getOrder
API to get a list of orders but I am unable to get RDT because I need to access buyerInfo and shipping address.I have followed this sample code here:
https://github.com/amzn/selling-partner-api-models/blob/main/clients/sample-code/RestrictedDataTokenWorkflow.java
But I always get 403 error when I try to get the RDT. This is the code:
And this is the response header:
awsAuthenticationCredentials
,awsAuthenticationCredentialsProvider
andlwaAuthorizationCredentials
should be correct since I am able to call other endpoints (not restricted resources).The code was generated using the following command:
and config.json:
Thanks!