Wez Furlong氏による、OpenIDとTypeKey認証を行うための、OpenSSLエクステンションのパッチが公開されています。このパッチを使用すると、PHPのアプリケーションにて、OpenIDとTypeKey認証を簡単に実装できます。
Wez Furlong氏による、OpenIDとTypeKey認証を行うための、OpenSSLエクステンションのパッチが公開されています。このパッチを使用すると、PHPのアプリケーションにて、OpenIDとTypeKey認証を簡単に実装できます。
パッチ自体は、このURLからダウンロードできます。Furlong氏のサーバー上でのPHP5にて動作を確認されているという事ですが、PHP4でも動作するだろうと、同氏は述べています。
Associateリクエスト
Associateリクエストを行い、キーを生成、交換することで、OpenIDサーバーとの関係を構築できます。このリクエストの結果は、同じサーバーを認証する場合の、ユーザー認証に使用できます。このコードは以下のようになります。
<?php $assoc = array(); $crypto = array(); $dh = openssl_dh_generate_key(OPENID_P_VALUE, '2'); foreach (openssl_dh_get_params($dh) as $n => $v) { $crypto[$n] = openssl_bignum_to_string($v, 10); } $params = array( 'openid.mode' => 'associate', 'openid.assoc_type' => 'HMAC-SHA1', 'openid.session_type' => 'DH-SHA1', 'openid.dh_modulus' => base64_encode( openssl_bignum_to_string(OPENID_P_VALUE)), 'openid.dh_gen' => base64_encode( openssl_bignum_to_string('2')), 'openid.dh_consumer_public' => base64_encode( openssl_bignum_to_string($crypto['pub_key'])), ); $r = perform_openid_rpc($server, $params); // サーバーと通信する if ($r['session_type'] == 'DH-SHA1') { $s_pub = openssl_bignum_from_bin( base64_decode($r['dh_server_public'])); $dh_sec = openssl_dh_compute_key($dh, $s_pub); if ($dh_sec === false) { do { $err = openssl_error_string(); if ($err === false) { break; } echo "$err<br>\n"; } while (true); } $sh_sec = sha1($dh_sec, true); $enc_mac = base64_decode($r['enc_mac_key']); $secret = ''; for ($i = 0; $i < strlen($enc_mac); $i++) { $secret .= chr(ord($enc_mac[$i]) ^ ord($sh_sec[$i])); } $assoc['secret'] = $secret; $assoc['handle'] = $r['assoc_handle']; $assoc['assoc_type'] = $r['assoc_type']; $assoc['expires'] = time() + $r['expires_in']; } else { $assoc = false; } ?>
OpenIDサーバーにて認証を行ったら、先ほど$returnURLに指定したURLに、リダイレクトで戻ってきます。
<?php
$assoc = $this->associate($args['srv']);
$token_contents = '';
/* token_contentsハッシュの名前は、
接頭辞が付いていないことに注意が必要です */
foreach (explode(',', $_GET['openid_signed']) as $name) {
if ($name == 'return_to') {
$token_contents .= "$name:" . $_GET['openid_return_to'] . "\n";
} else {
$token_contents .= "$name:" . $_GET["openid_"
. str_replace('.', '_', $name)] . "\n";
}
}
$x = hash_hmac('sha1', $token_contents, $assoc['secret'], true);
$hash = base64_encode($x);
if ($hash === $_GET['openid_sig']) {
// 認証が成功した
return true;
}
/* 何らかの理由で認証が失敗した */
$params = array();
$signed = explode(',', $_GET['openid_signed']);
$signed = array_merge($signed, array('assoc_handle',
'sig', 'signed', 'invalidate_handle'));
foreach ($signed as $name) {
$k = "openid_" . str_replace('.', '_', $name);
if (array_key_exists($k, $_GET)) {
$params["openid.$name"] = $_GET[$k];
}
}
$server = $args['srv'];
/* 証明書が壊れている。
* openid.modeをcheck_authentificationにして、認証のチェックを行う
*/
$params['openid.mode'] = 'check_authentication';
$res = perform_openid_rpc($server, $params);
if (isset($res['invalidate_handle'])) {
if ($res['invalidate_handle'] === $assoc['handle']) {
$this->associate($server, true);
}
}
return $res['is_valid'] === 'true';
?>
TypeKeyへの対応
TypeKeyからリダイレクトで戻ってきた際、シグネチャーを検証するスクリプトは以下の通りになります。
<?php
$keydata = array();
$regkeys = cache::httpGet(
'http://www.typekey.com/extras/regkeys.txt', 24*60*60);
if ($regkeys === false) {
die("urgh");
}
foreach (explode(' ', $regkeys) as $pair) {
list($k, $v) = explode('=', trim($pair));
$keydata[$k] = $v;
}
$sig = str_replace(' ', '+', $_GET['sig']);
$email = $_GET['email'];
$name = $_GET['name'];
$nick = $_GET['nick'];
$ts = $_GET['ts'];
$msg = "$email::$name::$nick::$ts::" . TYPEKEY_TOKEN;
if (time() - $ts > 300) {
die("possible replay");
}
list($r_sig, $s_sig) = explode(':', $sig, 2);
$r_sig = base64_decode($r_sig);
$s_sig = base64_decode($s_sig);
$valid = openssl_dsa_verify(sha1($msg, true),
openssl_bignum_from_bin($r_sig),
openssl_bignum_from_bin($s_sig),
$keydata['p'], $keydata['q'],
$keydata['g'], $keydata['pub_key']);
?>
(PHPプロ!)
関連リンク
転載元
PHPプロ!:最新のPHPニュース
この記事は参考になりましたか?
- この記事の著者
-
PHPプロ!(PHPプロ!)
「PHPプロ!」は、アシアル株式会社が運営するPHP開発者のためのポータル&コミュニティサイトです。同サイトでは、PHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座、PHP中級者のためのTIPSメーリングリスト、中・上級者向けの技術ノウハウ満載のPHPプロ!マガジンの提供など、PHP開発...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

