Cómo firmar una solicitud de servicio web de Amazon en .NET con SOAP y sin WSE

La API de publicidad de productos de Amazon (anteriormente, Amazon Associates Web Service o Amazon AWS) ha implementado una nueva regla que es, hasta el 15 de agosto de 2009, que todas las solicitudes de servicios web deben estar firmadas. Han proporcionado código de muestra en su sitio que muestra cómo hacer esto en C # usando REST y SOAP. La implementación que estoy usando es SOAP. Puedes encontrar el código de muestraaquí, No lo estoy incluyendo porque hay una cantidad justa.

El problema que tengo es que su código de ejemplo usa WSE 3 y nuestro código actual no usa WSE. ¿Alguien sabe cómo implementar esta actualización con solo usar el código generado automáticamente desde el WSDL? Me gustaría no tener que cambiar a WSE 3 ahora mismo si no tengo que hacerlo ya que esta actualización es más un parche rápido que nos retiene hasta que podamos implementar esto completamente en la versión dev actual (agosto En tercer lugar, están empezando a eliminar 1 de cada 5 solicitudes, en el entorno real, si no están firmadas, lo que es una mala noticia para nuestra aplicación).

Aquí hay un fragmento de la parte principal que hace la firma real de la solicitud SOAP.

class ClientOutputFilter : SoapFilter
{
    // to store the AWS Access Key ID and corresponding Secret Key.
    String akid;
    String secret;

    // Constructor
    public ClientOutputFilter(String awsAccessKeyId, String awsSecretKey)
    {
        this.akid = awsAccessKeyId;
        this.secret = awsSecretKey;
    }

    // Here's the core logic:
    // 1. Concatenate operation name and timestamp to get StringToSign.
    // 2. Compute HMAC on StringToSign with Secret Key to get Signature.
    // 3. Add AWSAccessKeyId, Timestamp and Signature elements to the header.
    public override SoapFilterResult ProcessMessage(SoapEnvelope envelope)
    {
        var body = envelope.Body;
        var firstNode = body.ChildNodes.Item(0);
        String operation = firstNode.Name;

        DateTime currentTime = DateTime.UtcNow;
        String timestamp = currentTime.ToString("yyyy-MM-ddTHH:mm:ssZ");

        String toSign = operation + timestamp;
        byte[] toSignBytes = Encoding.UTF8.GetBytes(toSign);
        byte[] secretBytes = Encoding.UTF8.GetBytes(secret);
        HMAC signer = new HMACSHA256(secretBytes);  // important! has to be HMAC-SHA-256, SHA-1 will not work.

        byte[] sigBytes = signer.ComputeHash(toSignBytes);
        String signature = Convert.ToBase64String(sigBytes); // important! has to be Base64 encoded

        var header = envelope.Header;
        XmlDocument doc = header.OwnerDocument;

        // create the elements - Namespace and Prefix are critical!
        XmlElement akidElement = doc.CreateElement(
            AmazonHmacAssertion.AWS_PFX, 
            "AWSAccessKeyId", 
            AmazonHmacAssertion.AWS_NS);
        akidElement.AppendChild(doc.CreateTextNode(akid));

        XmlElement tsElement = doc.CreateElement(
            AmazonHmacAssertion.AWS_PFX,
            "Timestamp",
            AmazonHmacAssertion.AWS_NS);
        tsElement.AppendChild(doc.CreateTextNode(timestamp));

        XmlElement sigElement = doc.CreateElement(
            AmazonHmacAssertion.AWS_PFX,
            "Signature",
            AmazonHmacAssertion.AWS_NS);
        sigElement.AppendChild(doc.CreateTextNode(signature));

        header.AppendChild(akidElement);
        header.AppendChild(tsElement);
        header.AppendChild(sigElement);

        // we're done
        return SoapFilterResult.Continue;
    }
}

Y eso se llama así cuando se realiza la llamada del servicio web real

// create an instance of the serivce
var api = new AWSECommerceService();

// apply the security policy, which will add the require security elements to the
// outgoing SOAP header
var amazonHmacAssertion = new AmazonHmacAssertion(MY_AWS_ID, MY_AWS_SECRET);
api.SetPolicy(amazonHmacAssertion.Policy());

Respuestas a la pregunta(4)

Su respuesta a la pregunta