SignatureDoesNotMatch
Amazon Web Services(AWS)の「Product Advertising API Signed Requests Sample Code」を利用して、リクエストを署名付きにする際に、ハマった。。。
原因は、apache commons-codecのバージョンが異なったこと。本記事を作成時点での最新版は1.4であるが、AWSで署名付きのリクエスト(URL)を作成する際は、1.3を使用しなければ動作しない。
AWSのAPI解説ページのコメント欄に注意書きがあった。コメントは見ていなかったよ。。。
下記に問題とエラーメッセージ、振り返りなどをメモしておく。
【問題】
・署名付きリクエストを作成するヘルパークラスを実装し、署名付きURLを作成したが、署名が正しくないと言われる。
【AWSからのレスポンス】
<?xml version="1.0"?> <ItemSearchErrorResponse xmlns="http://ecs.amazonaws.com/doc/2010-11-01/"> <Error> <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>a734c827-efe9-46bf-97fe-58a2d57c7110</RequestID> </ItemSearchErrorResponse>
【解決までの道のり】
①AWSのレスポンスに、「Check your AWS Secret Access Key and signing method」とあるので、まずは、AWS Secret Access Keyを確認。問題なかった。
signing methodは、AWSが提供しているものだから、確認しなかった。
②AmazonのSigned Requests Helperページで作成した署名付きのURLと、私のアプリで作成した署名付きURLを比較。違いが見られない。。。
③基本にもどり、マニュアルを見直す。コメント欄に次の記述を発見。かなり落ちこんだ。。。
Use Commons Codec Version 1.3 (commons-codec-1.3.jar) and the requests are signed properly.
The 1.4 Version of the Commons Codec does not sign the requests properly with the code as is.
【振り返り】
・マニュアルはしっかり読みましょう。
・Commons Codecはどこで使用しているのか。
Base64エンコーディングする際に、使用する。下記は、署名付きリクエストを作成するメソッドで、「Base64 encoder = new Base64();」のBase64クラスがCommons Codecライブラリ提供メソッドである。
private String hmac(String stringToSign) { String signature = null; byte[] data; byte[] rawHmac; try { data = stringToSign.getBytes(UTF8_CHARSET); rawHmac = mac.doFinal(data); Base64 encoder = new Base64(); signature = new String(encoder.encode(rawHmac)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(UTF8_CHARSET + " is unsupported!", e); } return signature; }
commons-codec.1.3.jarとcommons-codec.1.4.jarとで、Base64の仕様の相違を調べておくべきだな。。。