Как подписать запрос веб-службы Amazon в .NET с SOAP и без WSE

API рекламы продуктов Amazon (ранее Amazon Associates Web Service или Amazon AWS) внедрил новое правило, согласно которому к 15 августа 2009 года все запросы веб-служб к ним должны быть подписаны. Они предоставили пример кода на своем сайте, показывающий, как сделать это в C #, используя REST и SOAP. Реализация, которую я использую, - SOAP. Вы можете найти образец кодаВотЯ не включаю его, потому что есть изрядное количество.

Проблема, с которой я сталкиваюсь, состоит в том, что их пример кода использует WSE 3, а наш текущий код не использует WSE. Кто-нибудь знает, как реализовать это обновление, просто используя автоматически сгенерированный код из WSDL? Мне бы не хотелось переключаться на WSE 3 прямо сейчас, если бы я не нуждался в этом, так как это обновление - скорее быстрый патч, который держит нас, пока мы не сможем полностью реализовать это в текущем версия для разработчиков (3 августа они начинают сбрасывать 1 из 5 запросов в реальной среде, если они не подписаны, что является плохой новостью для нашего приложения).

Вот фрагмент основной части, которая выполняет фактическое подписание запроса 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;
    }
}

И это вызывается вот так при совершении реального вызова веб-службы

// 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());

Ответы на вопрос(4)

Ваш ответ на вопрос