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開発...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です