0

I want to get the details (Price, sorting ...) of the products that I have been querying for a long time from amazon. But I was only able to generate the following answer with the following koc. The problems I encountered are as follows;

1- I am getting timestamp error.

2- I was unable to POST the message below.

Can you help me with these two issues?

Note: I am using Anypoint Studio 7.11.1. I can post the answer in java with https reqeuest connector.

Java Code:

package com.amazonservices.mws.products;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.util.TimeZone;
import java.util.Date;

public class signature {
    private static final String CHARACTER_ENCODING = "UTF-8";
    final static String ALGORITHM = "HmacSHA256";
  
    
    public static void main() throws Exception {
        String secretKey = "***";
        String serviceUrl = "https://mws.amazonservices.com/";

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = new Date();  
        String timestamp = df.format(date); 
        
        HashMap<String, String> parameters = new HashMap<String,String>();

        parameters.put("AWSAccessKeyId", urlEncode("***"));
        parameters.put("Action", urlEncode("GetMatchingProductForId"));
        parameters.put("IdList.Id.1", urlEncode("9781933988665"));
        parameters.put("IdType", urlEncode("EAN"));
        parameters.put("SellerId", urlEncode("***"));
        parameters.put("SignatureMethod", urlEncode(ALGORITHM));
        parameters.put("SignatureVersion", urlEncode("2"));
        parameters.put("Timestamp", urlEncode(timestamp));
        parameters.put("Version", urlEncode("2011-10-01"));


        String formattedParameters = calculateStringToSignV2(parameters,
            serviceUrl);

        String signature = sign(formattedParameters, secretKey);

        // Add signature to the parameters and display final results
        parameters.put("Signature", urlEncode(signature));      
        
        System.out.println(calculateStringToSignV2(parameters,
            serviceUrl));
    }


    private static String calculateStringToSignV2(
        Map<String, String> parameters, String serviceUrl)
            throws SignatureException, URISyntaxException {
        // Sort the parameters alphabetically by storing
        // in TreeMap structure
        Map<String, String> sorted = new TreeMap<String, String>();
        sorted.putAll(parameters);

        // Set endpoint value
        URI endpoint = new URI(serviceUrl.toLowerCase());

        // Create flattened (String) representation
        StringBuilder data = new StringBuilder();
        //data.append("POST\n");
        data.append(endpoint.getHost());
        data.append("\n/Products/2011-10-01");
        data.append("\n");

        Iterator<Entry<String, String>> pairs =
          sorted.entrySet().iterator();
        while (pairs.hasNext()) {
            Map.Entry<String, String> pair = pairs.next();
            if (pair.getValue() != null) {
                data.append( pair.getKey() + "=" + pair.getValue());
            }
            else {
                data.append( pair.getKey() + "=");
            }

            // Delimit parameters with ampersand (&)
            if (pairs.hasNext()) {
                data.append( "&");
            }
        }

        return data.toString();
    }

    /*
     * Sign the text with the given secret key and convert to base64
     */
    private static String sign(String data, String secretKey)
            throws NoSuchAlgorithmException, InvalidKeyException,
                   IllegalStateException, UnsupportedEncodingException {
        Mac mac = Mac.getInstance(ALGORITHM);
        mac.init(new SecretKeySpec(secretKey.getBytes(CHARACTER_ENCODING),
            ALGORITHM));
        byte[] signature = mac.doFinal(data.getBytes(CHARACTER_ENCODING));
        String signatureBase64 = new String(Base64.encodeBase64(signature),
            CHARACTER_ENCODING);
        return new String(signatureBase64);
    }

    private static String urlEncode(String rawValue) {
        String value = (rawValue == null) ? "" : rawValue;
        String encoded = null;

        try {
            encoded = URLEncoder.encode(value, CHARACTER_ENCODING)
                .replace("+", "%20")
                .replace("*", "%2A")
                .replace("%7E","~");                ;
        } catch (UnsupportedEncodingException e) {
            System.err.println("Unknown encoding: " + CHARACTER_ENCODING);
            e.printStackTrace();
        }

        return encoded;
    }
  }

Code Output:

AWSAccessKeyId=&Action=GetMatchingProductForId&SellerId=&Signature=ehjKNnTB5vhrOW3J1yWSz2T7c%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&SubmittedFromDate=2013-05-01T12%3A00%3A00Z&Timestamp=2013-05-02T16%3A00%3A00Z&Version=2011-10-01

Mulesoft Version: 7.11.1

Application XML Detail:

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
    <flow name="awsFlow" doc:id="eeb85ef5-48cb-4c41-94ba-0e97a0765021" >
        <scheduler doc:name="Scheduler" doc:id="f21548f8-1a12-4efa-adf8-27988ac587c5" >
            <scheduling-strategy >
                <fixed-frequency />
            </scheduling-strategy>
        </scheduler>
        <ee:transform doc:name="Timestamp" doc:id="457efcd6-1388-49fe-88a8-f3d781d17593" >
            <ee:message >
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="requestmws" ><![CDATA[%dw 2.0
output application/json
fun getFormattedDate()=(now() >> "UTC") as String {format: "YYYY-MM-dd"} ++ "T" ++ (now() >> "UTC") as String {format: "HH:mm:ss"} ++ "Z"
---
{
    myDate:"mws.amazonservices.com/Products/2011-10-01?AWSAccessKeyId=AKIAI56GX43PIHX4C7XA&Action=GetMatchingProductForId&IdList.Id.1=9781933988665&IdType=EAN&MarketplaceId=ATVPDKIKX0DER&SellerId=A28MSXET37R4N7&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2011-10-01&Timestamp=" ++ getFormattedDate() replace (':') with ('%3A')
}]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
        <ee:transform doc:name="Transform Message" doc:id="5b556411-1a0a-4d31-b536-48245baf3e0e" >
            <ee:message >
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="signature" ><![CDATA[%dw 2.0
import dw::Crypto
output application/json
---
{ "HMACWith" : Crypto::HMACWith("c4AL2hA6TQQ+vhiAti7OHQI10g7Q9bvOzVHfHOEn" as Binary, vars.requestmws.myDate as Binary, "HmacSHA256") }]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
        <ee:transform doc:name="Transform Message" doc:id="ef709e54-4f12-4db8-9088-9ccb203fda07">
            <ee:message>
                <ee:set-payload><![CDATA[%dw 2.0
output application/java
---
{
    b : vars.requestmws.myDate ++ "&Signature=" ++ vars.signature.HMACWith
}]]></ee:set-payload>
            </ee:message>
        </ee:transform>
        <http:request method="POST" doc:name="Request" doc:id="9301bca2-067f-48a1-badc-4dd6c03a288d" url='#["https://" ++ payload.b]'>
            <http:headers ><![CDATA[#[output application/java
---
{
    "User-Agent" : "Java/1.8.0_201",
    "Content-Type" : "text/xml"
}]]]></http:headers>
        </http:request>
        <error-handler >
            <on-error-continue enableNotifications="true" logException="true" doc:name="On Error Continue" doc:id="27be6630-7439-43c9-86b5-c53c6693f0c7" type="ANY">
                <logger level="INFO" doc:name="Logger" doc:id="077e3a7c-902a-48bc-aa8d-6a18af941487" message="#[message]"/>
            </on-error-continue>
        </error-handler>
    </flow>
</mule>

Thanks.

aled
  • 21,330
  • 3
  • 27
  • 34
  • Hi @Muhammed. You should include in your question the actual error details you are experiencing. Kindly read https://stackoverflow.com/help/how-to-ask for more tips on how to improve your question. I see that you are doing this is Java code, so there is no Mule Runtime dependencies here, it is a pure Java and Amazon question. Any reasons not to use Mule HTTP Request connector? Note that the product is Mule, not MuleSoft. MuleSoft is the company's name. Please share the version of Mule used to execute the project in Studio, and the version of the Java module. – aled Mar 22 '22 at 13:32

1 Answers1

0

Since you are apparently executing in some release of Mule 4, you could build the same URL using DataWeave builtin functions.

For example the HMACWith() function will create the signature in one step.

Unless you have hard requirements to implement this in Java, you can just use the HTTP Request operation you can just add the query parameters you build in DataWeave expressions and it will take care of encoding and all the implementation details of performing the HTTP request.

aled
  • 21,330
  • 3
  • 27
  • 34
  • Your solution made me very excited. I turned to java for Signature, but the method you specified worked. The 2 problems I'm having at the moment are as follows; 1- In the request I sent, the answer was: " failed: forbidden (403)." 2- To try, I write only 1 EAN in the "IdList.Id.1" field, but after successful, I want to send an array to this field. Can you share your comments on these two issues? I am sharing the Mulesoft details above. – Muhammed SARIKAYA Mar 23 '22 at 16:45
  • 403 indicates that the request is not authorized. Maybe you are missing some parameter that is required for authentication. Does it work testing with Postman or other tool? I found this list of required parameters for MWS: https://docs.developer.amazonservices.com/en_US/dev_guide/DG_RequiredRequestParameters.html – aled Mar 23 '22 at 17:33
  • Hi aled, when I try with postman and MWS Scratchpad, it is successfull with parameters but I get error with mule. – Muhammed SARIKAYA Mar 23 '22 at 19:13
  • Try comparing the HTTP request from Postman and the HTTP request (use Code / HTTP request) and from the Mule application (use HTTP wire logging) to see if there are any differences, other than maybe the time. Any missing parameters, or incorrect characters may throw the error. – aled Mar 23 '22 at 21:58
  • you are doing several string manipulations that are probably not needed, like replacing the colon. Are you sure you calculating the hash of the right input? – aled Mar 23 '22 at 22:01