Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Amazon MWS | RestSharp | The request signature we calculated does not match the signature you provid
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

Amazon MWS | RestSharp | The request signature we calculated does not match the signature you provid

beantworten | zitieren | melden

Hallo zusammen,

ich möchte über die Amazon MWS API Schnittstelle sämtliche Daten (bspw. Orders) abrufen. Leider bekomme ich jedoch jedesmal diese Fehlermeldung:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <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.</Message>
  </Error>
  <RequestID>9f03f5b0-e4e4-4766-a554-00ff970b6b8c</RequestID>
</ErrorResponse>

Das wunder mich, da ich die selbe Signatur errechne, wie auch auf dem Amazon Scratchpad (https://mws.amazonservices.de/scratchpad/index.html) berechnet wird (Jedoch nur wenn ich den selben Zeitstempel eintrage, wie auch online generiert wird).

Folgend meine Methode und auch die Funktion zum errechnen der Signatur. Ich komme gerade nicht weiter und hoffe einer von euch weis woran es liegt.

Könnte es sein, dass es am RestCLient liegt? Dieser fügt standartmäßig noch 1-2 weitere Parameter hinzu?

public async void FetchOrders()
{
    RestClient client = new RestClient("https://mws.amazonservices.de");
    client.DefaultParameters.Clear();
    client.ClearHandlers();

    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("AWSAccessKeyId", "xxxxxxxxxx");
    parameters.Add("Action", "ListOrders");
    parameters.Add("CreatedAfter", "2018-01-01T11:34:00Z");
    parameters.Add("MarketplaceId.Id.1", "A1PA6795UKMFR9");
    parameters.Add("SellerId", "xxxxxxxxx");
    parameters.Add("SignatureVersion", "2");
    parameters.Add("Timestamp", DateTime.UtcNow.ToString("s") + "Z");
    parameters.Add("Version", "2013-09-01");

    RestRequest request = new RestRequest("Orders/2013-09-01/", Method.POST);

    string signature = AmzLibrary.SignParameters(parameters, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    request.AddParameter("Signature", signature);

    foreach (KeyValuePair<string, string> keyValuePair in parameters)
    {
        request.AddParameter(keyValuePair.Key, keyValuePair.Value);
    }

    IRestResponse result = await client.ExecuteTaskAsync(request);
}



public static class AmzLibrary
{
    public static string GetParametersAsString(IDictionary<String, String> parameters)
    {
        StringBuilder data = new StringBuilder();
        foreach (String key in (IEnumerable<String>)parameters.Keys)
        {
            String value = parameters[key];
            if (value != null)
            {
                data.Append(key);
                data.Append('=');
                data.Append(UrlEncode(value, false));
                data.Append('&');
            }
        }
        String result = data.ToString();
        return result.Remove(result.Length - 1);
    }

    public static String SignParameters(IDictionary<String, String> parameters, String key)
    {
        String signatureVersion = parameters["SignatureVersion"];

        KeyedHashAlgorithm algorithm = new HMACSHA1();

        String stringToSign = null;
        if ("2".Equals(signatureVersion))
        {
            String signatureMethod = "HmacSHA256";
            algorithm = KeyedHashAlgorithm.Create(signatureMethod.ToUpper());
            parameters.Add("SignatureMethod", signatureMethod);
            stringToSign = CalculateStringToSignV2(parameters);
        }
        else
        {
            throw new Exception("Invalid Signature Version specified");
        }

        return Sign(stringToSign, key, algorithm);
    }

    private static String CalculateStringToSignV2(IDictionary<String, String> parameters)
    {
        StringBuilder data = new StringBuilder();
        IDictionary<String, String> sorted =
              new SortedDictionary<String, String>(parameters, StringComparer.Ordinal);
        data.Append("POST");
        data.Append("\n");
        Uri endpoint = new Uri("https://mws.amazonservices.de/Orders/2013-09-01");

        data.Append(endpoint.Host);
        if (endpoint.Port != 443 && endpoint.Port != 80)
        {
            data.Append(":")
                .Append(endpoint.Port);
        }
        data.Append("\n");
        String uri = endpoint.AbsolutePath;
        if (uri == null || uri.Length == 0)
        {
            uri = "/";
        }
        data.Append(UrlEncode(uri, true));
        data.Append("\n");
        foreach (KeyValuePair<String, String> pair in sorted)
        {
            if (pair.Value != null)
            {
                data.Append(UrlEncode(pair.Key, false));
                data.Append("=");
                data.Append(UrlEncode(pair.Value, false));
                data.Append("&");
            }

        }

        String result = data.ToString();
        return result.Remove(result.Length - 1);
    }

    private static String UrlEncode(String data, bool path)
    {
        StringBuilder encoded = new StringBuilder();
        String unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~" + (path ? "/" : "");

        foreach (char symbol in System.Text.Encoding.UTF8.GetBytes(data))
        {
            if (unreservedChars.IndexOf(symbol) != -1)
            {
                encoded.Append(symbol);
            }
            else
            {
                encoded.Append("%" + String.Format("{0:X2}", (int)symbol));
            }
        }

        return encoded.ToString();

    }

    private static String Sign(String data, String key, KeyedHashAlgorithm algorithm)
    {
        Encoding encoding = new UTF8Encoding();
        algorithm.Key = encoding.GetBytes(key);
        return Convert.ToBase64String(algorithm.ComputeHash(
            encoding.GetBytes(data.ToCharArray())));
    }
}
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.310

beantworten | zitieren | melden

Jetzt musst Du natürlich Glück haben und jemanden finden, der genau diese API kennt...

Hast Du mal auf GitHub nach vergleichbarem Code geschaut, wie dieser die Signatur ausrechnet?
Kann mir jetzt nicht vorstellen, dass es an der Amazon-Seite liegt.

Mal im Fiddler geschaut, ob die URL, die Du erzeugst, überhaupt gültig ist und so sind, wie Du es denkst?
Sieht etwas abenteuerlich aus, dass Du nicht einfach die Framework-Methoden für Queries und Parameter verwendest.
private Nachricht | Beiträge des Benutzers
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Hast Du mal auf GitHub nach vergleichbarem Code geschaut, wie dieser die Signatur ausrechnet?
Kann mir jetzt nicht vorstellen, dass es an der Amazon-Seite liegt.

Ich habe dazu kein GitHub Repo gefunden. Als Vorlage habe ich mir die Berechnung aus deren Beispiel geklaut https://developer.amazonservices.de/doc/bde/feeds/v20090101/cSharp.html. Ich denke auch nicht das diese falsch ist, da sowohl im C# als auch im Scratchpad die selbe Signatur errechnet wird.
Zitat von Abt
Mal im Fiddler geschaut, ob die URL, die Du erzeugst, überhaupt gültig ist und so sind, wie Du es denkst.

Nein habe ich nicht. Wenn ich allerdings parameter vergesse zu übermitteln, erhalte eine dementsprechende Fehlermeldung. "Parameter Signatur fehlt", "Parameter Action fehlt; ist nicht gültig" etc..
Zitat von Abt
Sieht etwas abenteuerlich aus, dass Du nicht einfach die Framework-Methoden für Queries und Parameter verwendest.

Was meinst du damit? Von welchen Framework-Methoden sprichst du? Ich benutze bspw. das Dictionary nur, da die Amazon Klasse ein Dict als Parameter zur Berechnung der Signatur verlangt.
private Nachricht | Beiträge des Benutzers
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

beantworten | zitieren | melden

Ich habe soeben mal diese Bibliothek (Chilkat C# library) getestet und musste feststellen, dass es damit funktioniert. Nun ist die Frage warum es bei mir nicht funktioniert?!

https://www.example-code.com/csharp/mws_list_orders.asp

Da dies mein erstes Projekt mit einer RestAPI ist, steh' ich ein bisschen auf dem Schlauch.

Danke im Voraus!
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

Ich würde jetzt mal sagen, das Problem hat gar nichts mit REST & Co. zu tun.

Die Parameter müssen für die Signierung kodiert werden, was AmzLibrary.GetParametersAsString auch macht.

Der RestClient kodiert diese Parameter für den Request allerdings auch und genau da würde ich sagen liegt das Problem. Ein Leerzeichen kann als + oder als %20 kodiert werden. Der Sinn ist der gleiche. Für die Signierung ist das aber eben nicht das Gleiche.
private Nachricht | Beiträge des Benutzers
Coffeebean
myCSharp.de - Team

Avatar #avatar-3295.gif


Dabei seit:
Beiträge: 2.209
Herkunft: Deutschland/Schweiz

beantworten | zitieren | melden

Hallo d.jonas,

du kannst auch mit Tools wie "Fiddler" nachschauen, welche HTTP-Requests rausgehen und die Requests mal vergleichen.

Gruss

Coffeebean
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.310

beantworten | zitieren | melden

Zitat von d.jonas
I...musste feststellen, dass es damit funktioniert. Nun ist die Frage warum es bei mir nicht funktioniert?!

... deswegen hab ich Dich auf Fiddler hingewiesen. Es ist offensichtlich, dass es an Deinem Code liegt.

Dort kannst Du sehen - und vergleichen - was tatsächlich an die API geschickt wird und wo der Unterschied liegt.

Und ich hab Dich auf die Framework-Elemente verwiesen, da ich - wie Sir Rufo auch - die Vermutung hatte und habe, dass Du die Parameter in einem falschen Format an die API versendest.
Da ich selbst aber Deine HTTP Requests in Deinem Fiddler nicht sehe, muss man halt vermuten.
Analysieren und wirklich vergleichen kannst nur Du das.
private Nachricht | Beiträge des Benutzers
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

beantworten | zitieren | melden

Danke für eure Hilfe! Ich wollte gerade die beiden Requests miteinander vergleichen, jedoch wird der Traffic der "Chilkat" Bibliothek nicht aufgezeichnet, bei RestSharp geht das ohne Probleme. Gibt es hier spezielle Einstellungen vorzunehmen?

Folgendes habe ich schon probiert: http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/ConfigureDotNETApp Leider ohne Erfolg.



    GlobalProxySelection.Select = new WebProxy("127.0.0.1", 8888);

  <configuration>
   <system.net>
    <defaultProxy>
     <proxy bypassonlocal="false" usesystemdefault="true" />
    </defaultProxy>
   </system.net>
  </configuration>
private Nachricht | Beiträge des Benutzers
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

beantworten | zitieren | melden

Thread kann geschlossen werden!
Ich bedanke mich nochmal für eure Hilfe, dank Fiddler bin ich auf die Lösung gekommen.

Das Problem war das "/" am Ende:
Falsch

RestRequest request = new RestRequest("Orders/2013-09-01/", Method.POST);

Richtig

RestRequest request = new RestRequest("Orders/2013-09-01", Method.POST);

Falls jemand dennoch die Lösung weis, warum die externe Bibliothek nicht von Fiddler geloggt wird, bin ich gerne offen.

Gruß
d.jonas
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.310

beantworten | zitieren | melden

HTTPS? Muss im Fiddler extra aktiviert werden.
Dann kann Fiddler HTTPS aufbrechen.
private Nachricht | Beiträge des Benutzers
d.jonas
myCSharp.de - Member



Dabei seit:
Beiträge: 21
Herkunft: Bayern

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
HTTPS? Muss im Fiddler extra aktiviert werden.
Ja das hatte ich gemacht, sonst wird mir auch die RestSharp Kommunikation nicht angezeigt. Dennoch wird mir die Kommunikation mit der Chilkat Bibliothek überhaupt nicht angezeigt.
private Nachricht | Beiträge des Benutzers