Amazon Product Advertising API(以前のAmazon Associates WebServiceまたはAmazonAWS)は、2009年8月15日までにすべてのWebサービスリクエストに署名する必要があるという新しいルールを実装しました。彼らは、RESTとSOAPの両方を使用してC#でこれを行う方法を示すサンプルコードをサイトに提供しています。私が使用している実装はSOAPです。サンプルコードはここにありますが、かなりの量があるため、ここには含めていません。
私が抱えている問題は、サンプルコードがWSE 3を使用しており、現在のコードがWSEを使用していないことです。WSDLから自動生成されたコードを使用するだけでこの更新を実装する方法を知っている人はいますか?このアップデートは、現在の開発バージョン(8月)で完全に実装できるようになるまで、私たちを引き留めるためのより迅速なパッチであるため、必要がなければ、今すぐWSE3のものに切り替える必要はありません。 3番目に、署名されていない場合、ライブ環境で5つのリクエストのうち1つをドロップし始めています。これは、アプリケーションにとって悪いニュースです)。
これは、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;
}
}
そして、実際のWebサービス呼び出しを行うと、このように呼び出されます
// 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());