WSSE認証に必要なこと
リクエストのHTTPヘッダに、次の内容を含めて送信します。
Username
はてなダイアリーAtomPubとは - はてなキーワード
ユーザー名。(はてなアカウントのid)
Nonce
HTTPリクエスト毎に生成したセキュリティ・トークン*1
Created
Nonceが作成された日時をISO-8601表記で記述したもの
PasswordDigest
Nonce, Created, パスワード(はてなアカウントのパスワード)を文字列連結しSHA1アルゴリズムでダイジェスト化して生成された文字列を、Base64エンコードした文字列
ポイントとしては以下の3点をCocoa(Objective-C)でどう実現するかということになります。
- SHA-1 ダイジェスト
- Base64エンコード
- ISO-8601表記の日時
SHA-1 ダイジェストを生成する
OpenSSLのライブラリを使用すると簡単です。
cocoacco: OpenSSL用フレームワーク
とりあえずAPIは叩けた : As Sloth As Possible
下記のコード(CocoaCryptoHashing)を使用しました。
Stoneship > Software
http://projects.stoneship.org/hg/cocoa_crypto_hashing/
CocoaCryptoHashingはNSStringとNSDataのカテゴリとして実装されています。sha1HexHashは戻り値がNSString、sha1HashはNSDataになっています。
パスワードダイジェストは最終的にBase64エンコードをするので、NSData型で返しています。(後述のBase64のライブラリはNSDataのカテゴリとして実装されているため)
NSString *nonce = [[NSString stringWithFormat:@"%@%d", formattedDate, rand()] sha1HexHash]; NSString *passwordDigest = [[[NSString stringWithFormat:@"%@%@%@", nonce, formattedDate, password] sha1Hash] stringEncodedWithBase64];
Base64エンコード
下記のサイトにあるコードを使用しました。
NSDataにBase64のエンコード・デコード機能を追加する
NSDataのカテゴリーとして実装されているので、Base64の文字列を得るためにはNSStringを一度NSDataに変換する必要があります。
簡単に - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding メソッドを使いました。
NSString *nonce = [[NSString stringWithFormat:@"%@%d", formattedDate, rand()] sha1HexHash]; NSString *base64 = [[nonce dataUsingEncoding:NSASCIIStringEncoding] stringEncodedWithBase64];
別の方法も参考として挙げておきます。
MacBookでプログラミング : Cocoaプログラミングで文字列をBase64でエンコードしたい - livedoor Blog(ブログ)
http://www.cocoadev.com/index.pl?BaseSixtyFour
ISO-8601表記の日時
次のような表記になります。
2004-04-01T12:00:00+09:00
ISO 8601 - Wikipedia
日付のフォーマットはNSDateFormatterを使います。
書式の表記については、Mac OS X 10.3以前と10.4以降で変更があり、10.4以降ではUnicode standardの記法を使用します。
また、iPhone OS 2.1から、時刻の24時間表時をオフにした場合、午前・午後の文字列が含まれて返ってきます。
そのため、午前もしくは午後の文字列を取り去る処理が必要になります。
NSDate *now = [[NSDate date] retain]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:sszzz"]; NSString *dateString = [dateFormatter stringFromDate:now]; dateString = [dateString stringByReplacingOccurrencesOfString:[NSString stringWithUTF8String:"午前"] withString:@""]; dateString = [dateString stringByReplacingOccurrencesOfString:[NSString stringWithUTF8String:"午後"] withString:@""];
最終的に、以下のコードになりました。
srand(time(nil)); NSString *nonce = [[NSString stringWithFormat:@"%@%d", formattedDate, rand()] sha1HexHash]; NSString *passwordDigest = [[[NSString stringWithFormat:@"%@%@%@", nonce, formattedDate, password] sha1Hash] stringEncodedWithBase64]; NSString *base64 = [[nonce dataUsingEncoding:NSASCIIStringEncoding] stringEncodedWithBase64]; NSString *credentials = [NSString stringWithFormat: @"UsernameToken Username=\"%@\", " @"PasswordDigest=\"%@\", " @"Nonce=\"%@\", " @"Created=\"%@\"", userName, passwordDigest, base64, formattedDate];