SOAPの認証
AWSで認証が必要な場合、自力で署名を行う必要があります。ただ、署名と言ってもメッセージ全体をハッシュしたりするわけではなく、特定のフォーマットに従った文字列を署名(ハッシュ)することになります。結構簡単です。
AWSが提供するIDとキー
- AccessKeyID … ユーザのID。他人に知られても別に問題はありません。
- SecretAccessKey … アクセスする為の秘密鍵。他人に知られてはダメです。これを使用し、署名を行います。署名に関しては後ほど述べます。
S3では使用しませんが、他にもクライアント証明書が用意されています。
署名
Timestampです。時間はユニバーサル時間(グリニッジ標準時間)で記述する必要があり、フォーマットは2005-01-31T23:59:59.183Zの様にします。このTimestampの時間とAWSのサーバの時間が15分以上ずれると失敗となるので注意しましょう。
署名です。署名は"AmazonS3" + OPERATION(メソッド名) + Timestampのハッシュ値を取ります。ハッシュの計算はHMAC-SHA1で行います。文字エンコーディングの話が出ていないのですが、ASCII文字以外出てきそうにないので、UTF-16とかを指定しない限り大丈夫そうです…サンプルではUTF-8を使用していました。
注:DateTimeの精度についてですが、S3のサービスに合わせてミリ秒までの精度にする方が良いです。クライアント内部にキャッシュしているデータと比較したりする場合便利です。
// TimeStampのフォーマットとSignatureの計算に使用するデータのプリフィックス。
private const string c_sISODateFormat = "yyyy-MM-ddTHH:mm:ss.fffZ";
private const string c_sAmazonS3 = "AmazonS3";
// Timestamp用のDateTimeを取得
public DateTime Aws_GetDatestamp()
{
DateTime dteCurrentDateTime;
DateTime dteFriendlyDateTime;
dteCurrentDateTime = DateTime.Now;
dteFriendlyDateTime = new DateTime(dteCurrentDateTime.Year,
dteCurrentDateTime.Month, dteCurrentDateTime.Day,
dteCurrentDateTime.Hour, dteCurrentDateTime.Minute,
dteCurrentDateTime.Second,
dteCurrentDateTime.Millisecond, DateTimeKind.Local);
return dteFriendlyDateTime;
}
// グローバル時間(グリニッジ標準時間)に変換
public string Aws_GetISOtimeStamp(DateTime timeStamp)
{
string sISOtimeStamp;
sISOtimeStamp = timeStamp.ToUniversalTime().ToString(c_sISODateFormat, System.Globalization.CultureInfo.InvariantCulture);
return sISOtimeStamp;
}
// 署名
public string Aws_GetSignature(string operation, DateTime timeStamp)
{
string sSig_Raw;
string sSignature;
UTF8Encoding objUTF8Encoder;
HMACSHA1 objHMACSHA1;
sSig_Raw = c_sAmazonS3 + operation + Aws_GetISOtimeStamp(timeStamp);
objUTF8Encoder = new UTF8Encoding();
objHMACSHA1 = new HMACSHA1(objUTF8Encoder.GetBytes(m_sSecretAccessKey));
sSignature = Convert.ToBase64String(objHMACSHA1.ComputeHash(objUTF8Encoder.GetBytes(sSig_Raw.ToCharArray())));
return sSignature;
}
ちなみに、認証付きのSOAPでS3にアクセスする場合、必ずSSLでアクセスしなければなりません。