(前回)Cocoaの日々: Keychain Services 調査 (10) ID/パスワード入力例
さてそろそろコーディングに入ろう。検証のゴールは以前描いた処理フローを一通り確認できるようなサンプルアプリを作る。
(参考)Cocoaの日々: Keychain Services 調査 (9) 処理フロー
今回はまずパスワードの格納をやってみる。Mac Dev Center のコードを参考にしながら進めてみた。
Mac Dev Center: Keychain Services Programming Guide: Keychain Services Tasks for Mac OS X
機能は単純で "TEST"ボタンを押すと、Keychain に決まったパスワードを登録するというもの。
KeychainSample1AppDelegate.m
@implementation KeychainSample1AppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
-(IBAction)test:(id)sender
{
BOOL result = [[KeychainManager sharedManager]
storePasswordWithServiceName:@"TEST-1"
accountName:@"hashiguchi"
password:@"1234567"];
NSLog(@"result=%d", result);
}
@end
KeychainManager というクラスを用意し、そこで用意したパスワード格納メソッドを呼んでいる。
KeychainManager.m
@implementation KeychainManager
#pragma mark -
#pragma mark Initilizer and Deallocation
static KeychainManager* _sharedManager = nil;
+ (KeychainManager*)sharedManager
{
if (!_sharedManager) {
_sharedManager = [[KeychainManager alloc] init];
}
return _sharedManager;
}
- (void) dealloc
{
[super dealloc];
}
#pragma mark -
#pragma mark Store & Get a password
-(BOOL)storePasswordWithServiceName:(NSString*)serviceName accountName:(NSString*)accountName password:(NSString*)password
{
OSStatus status;
const char *serviceNameUTF8 = [serviceName UTF8String];
const char *accountNameUTF8 = [accountName UTF8String];
const char *passwordUTF8 = [password UTF8String];
status = SecKeychainAddGenericPassword(NULL,
strlen(serviceNameUTF8),
serviceNameUTF8,
strlen(accountNameUTF8),
accountNameUTF8,
strlen(passwordUTF8),
passwordUTF8,
NULL);
if (status == errSecSuccess) {
return YES;
} else {
NSLog(@"ERROR:SecKeychainAddGenericPassword:%d", status);
return NO;
}
}
KeychainManagerはシングルトンとした。
格納には SecKeychainAddGenericPassword を使う。
Mac Dev Center: Keychain Services Reference - SecKeychainAddGenericPassword
Sec系関数は Objective-C ではなくCの関数なので若干の変換が必要になる。文字列はすべて UTF8 変換した char配列とする。OSStatus SecKeychainAddGenericPassword ( SecKeychainRef keychain, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef );
なおビルドする時には Security.framework をリンクする必要がある。
これが無いとビルド時に怒られる。
さて実行してみよう。起動して "TEST"ボタンを押して Keychainへパスワードを登録する。その後、キーチェーン.app で探してみると...あった。
属性を見てみる。
名前と場所に serviceName が入っている。種類は自動的に「アプリケーションパスワード」が設定されるようだ。「パスワードを表示」にチェックを入れると Keychainのパスワード入力が求められた。
パスワードを入力すると、プログラムで設定した文字列が表示された。正しく格納されたようだ。
アクセス制御では、プログラムが自動的に信頼されたアプリの一覧に追加されている。
なおもう一度 "TEST"ボタンを押すと(すなわち SecKeychainAddGenericPassword を2度実行すると)エラーとなった。
KeychainSample1[10105:80f] result=1
KeychainSample1[10105:80f] ERROR:SecKeychainAddGenericPassword:-25299
KeychainSample1[10105:80f] result=0
Mac Dev Center: Keychain Services Reference
上記によれば、エラーコード -25299 は
errSecDuplicateItem
–25299 The item already exists.Available in Mac OS X v10.2 and later.