at posts/single.html

php-openid で mixi のコミュニティ認証を使う

「mixi openidに対応したファイルあぷろだ」が誰でも使える件を書くついでに、 PHP の OpenID ライブラリである php-openid ライブラリを使ってみた。 前に使ったときはバージョンが1系だったけど、今は2系が公開されている。

環境

MacOS X + PHP5.2.5

ダウンロード

php-openid ライブラリのページから最新のライブラリを取得する。 現時点では2.1.2が最新だった。

インストール

解凍してできた Auth ディレクトリを、これから作るサンプルプログラムと同じディレクトリにコピーする。 ちなみに、本格的に使うときは php.ini で指定する include_path に置く。 ちなみに、バージョン1系のときは Auth/OpenID と Service/Yadis だったのが、バージョン2系では Auth/OpenID と Auth/Yadis になってた。

使ってみる

まずはコミュニティ認証へのリクエストを送るサンプル

<?php
require_once('Auth/OpenID/Consumer.php');
require_once('Auth/OpenID/FileStore.php');
require_once('Auth/OpenID/SReg.php');

session_start();   # これをやらないとYadisライブラリでエラーになる
$serverUri = 'http://localhost/';
$returnTo = $serverUri . 'response.php';

$store = new Auth_OpenID_FileStore('/tmp/openid');
$consumer = new Auth_OpenID_Consumer($store);
$req = $consumer->begin('https://id.mixi.jp/community/1651291');
$redirectURL = $req->redirectURL($serverUri, $returnTo, false);

header("Location: $redirectURL");
?>

これを実行すると、以下のようにエラーになる。

Fatal error: Call to a member function redirectURL() on a non-object in /Users/machu/Sites/openid/request.php on line 13

コマンドラインから実行すると、こうなる。

Successfully fetched 'https://id.mixi.jp/community/1651291': GET response code 200
Got no response code when fetching https://mixi.jp/xrds_signon.pl
CURL error (60): SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Fatal error: Call to a member function redirectURL() on a non-object in /Users/machu/Sites/openid/request.php on line 13

どうやら、 https://id.mixi.jp/ へはアクセスできているけど、 https://mixi.jp/ へのアクセスに失敗しているみたい。 「certificate verify failed」と書かれているので、サーバ証明書の検証に失敗している。

PHPでSSL接続

「PHP mixi openid」でググると、cURL に HTTPS でアクセスできるように証明書を追加するというサイトが見つかった。 どうやら、OpenIDライブラリではSSL接続にcURLを使っているみたい。

コマンドラインで再現してみる。

$ curl https://id.mixi.jp/community/1651291
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.or
g/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
// 以下、mixiのHTMLが出力される

$ curl https://mixi.jp/xrds_signon.pl
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
More details here: http://curl.haxx.se/docs/sslcerts.html

やっぱり id.mixi.jp は OK で mixi.jp はダメ。

対策

ググって目につくのは、サーバ証明書のチェックを無効にする方法。

コマンドラインだと -k オプションをつける。

$ curl -k https://mixi.jp/xrds_signon.pl

PHP だと、 Auth/Yadis/ParanoidHTTPFetcher.php で curl_setopt() する。

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

でも、テスト時以外でこれをやっちゃだめ。 サーバ証明書をチェックしないってのは、SSLを使わないのと同じ。 何のために mixi が SSL を用意しているのか分かんなくなっちゃう。

ってことで、ちゃんと調べる。 curl が信頼するCA証明書のリストの指定方法はこれ。他にもあるかも。

  • /usr/share/curl/curl-ca-bundle.crt
  • --cacert オプションでCA証明書を渡す

デフォルトでは前者のファイル (curl-ca-bundle.crt) が優先される。 このファイルの中身を見てみると、 https://id.mixi.jp/ で使っているCA証明書 (GTE CyberTrust Global Root) は載っていたけど、 https://mixi.jp/ で使っているCA証明書 (AddTrust External CA Root) は載っていなかった。 ファイルの先頭に「Netscape Communicator 4.72's certificate」って書いてあるから、新しいCAが入っていないんだろうね。

ってことで、対策は2つ。

  • /usr/share/curl/curl-ca-bundle.crt に AddTrust のCA証明書を追加する
  • Auth/Yadis/ParanoidHTTPFetcher.php の curl_setopt で AddTrust のCA証明書を指定する

前者はcURLを使う全てのプログラムに影響があるので、AddTrustをどれだけ信頼するか、もしくはroot権限を持っているかどうかで対策が変わる。

ちなみに AddTrust の証明書は、 https://mixi.jp/ のページにアクセスして、ページ情報→セキュリティ→証明書の表示→詳細→証明書の階層でAddTrustを選択→書き出す→X.509証明書(PEM)でファイルに書き出せる(Firefox3の場合)。

cURL に HTTPS でアクセスできるように証明書を追加するでは以下のように書かれている。

証明書の保存形式を聞かれるので、X.509 Certificate with chain (PEM)を選択します。ここが重要です。 1つ上の X.509 Certificate (PEM) でよさそうですが、これだとうまくかないです。 ただの PEM だと証明書が1つしか入っていませんが、with chain の方だと3つ入っていて、これが何らかの意味があるみたいです。

これはたぶん、 AddTrust の証明書じゃなくて、AddTrust が発行した mixi 用のサーバ証明書を選択しちゃったんだと思う。 だから、chainにしてCA証明書を含めないとダメだったんだろうね。

関連する日記