第3回 Consumerの実装を知り、OpenIDを使ってみよう:OpenIDの仕様と技術(3)(3/3 ページ)
前回まではOpenIDの基礎知識として、根底にある考え方や用語を中心に解説してきました。今回はその準備を踏まえ、Perl、Catalystを活用し実際にConsumerサイトを構築してみましょう。(編集部)
Catalystを使ってConsumer側の認証プログラムを書く
今回はCatalystを使ってサンプルを記述していきます。Catalystそのものの使い方については、本記事で取り扱うべき範囲を超えているので必要以上に解説はしません。 またCatalystには、プラグインとしてCatalyst::Plugin::Authentication::Credential::OpenIDというモジュールが存在しますが、今回は学習のため、このモジュールを使わないで実装します。
今回サンプルソースコードを用意してみました。動作環境はLinux /MacOSXを想定しています。サンプルソースコードをダウンロードし、下記のようにコマンドを入力しましょう。
$ tar xfz OpenID-ConsumerApp-0.01.tar.gz $ cd OpenID-ConsumerApp-0.01 $ perl Makefile.PL
この時に必要なモジュールがインストールされていない場合は、
$ sudo make
でインストールされるかと思います。
さらに使い方ですが、
$ ./script/openid_consumerapp_server.pl -d -r
でdaemonとして起動しますので、ブラウザに http://localhost:3000/ と入力す るとサンプルプログラムを確認する事ができます。起動を停止するにはTERMシグナルをkillで送るか、C-cでSIGINTシグナルを送れば停止します。
【サンプルソースコード】
サンプルソースコードはこちらからダウンロードしてください。
http://www.atmarkit.co.jp/fsecurity/rensai/openid03/OpenID-ConsumerApp-0.01.tar.gz
認証フォームの作成
Catalystのプロジェクト名を“OpenID::ConsumerApp”で作成したとして以降を進めていきます。OpenID::ConsumerApp::Controller::Rootモジュール内のdefaultメソッドを次のようにします。
sub default : Private {
my ( $self, $c ) = @_;
$c->stash->{template} = "index.tt";
$c->forward('OpenID::ConsumerApp::View::TT');
}
ここでforward先にOpenID::ConsumerApp::View::TTを指定していますが、これはCatalyst::View::TTモジュールのサブクラスを指定しています。またstashのtemplateに代入してある値“index.tt”はテンプレートファイルになります。
localhostでopenid_consumerapp_server.plでCatalystを実行している場合は、http://localhost:3000/にアクセスすることで認証フォームが表示されます。
IdPへの問い合わせ機能の実装
次にOpenID::ConsumerApp::Controller::Loginモジュールを確認しましょう。その中のindex()メソッドを抜粋します。
sub index : Private {
my ( $self, $c ) = @_;
my $csr = Net::OpenID::Consumer->new(
ua => LWP::UserAgent->new,
cache => Cache::File->new(
cache_root => '/tmp/openid',
default_expires => '6000 sec'
),
consumer_secret => 'zigorou',
args => $c->req->params,
required_root => 'http://localhost:3000/',
debug => 1,
);
my $delayed_return = $c->req->param("mode") eq "checkid_setup" ? 1 : 0;
$c->log->debug("delayed_return : " . $delayed_return);
if (my $cident = $csr->claimed_identity($c->req->params->{openid_url})) {
my $check_url = $cident->check_url(
return_to => "http://localhost:3000/login/handler",
trust_root => "http://localhost:3000/",
delayed_return => $delayed_return
);
$c->res->redirect($check_url);
}
else {
$c->res->body("Can't create claimed identifier object.");
}
}
Net::OpenID::Consumerモジュールを実際に使う部分となります。この処理の中で必要になる処理をもう一度おさらいしましょう。
- IdPのエンドポイントURLの抽出(必要ならdelegateの解決)
- 必要ならばassociateモードの実行
- checkid_immediateまたはcheckid_setupモードの実行
- User-AgentをIdPにリダイレクト
実はこの4つの手続きのうち、最後の1つを除きすべてNet::OpenID::Consumerのcheck_url()メソッドが担当してくれます。そしてcheck_url()の戻り値が、まさに最後のリダイレクト先のURLなので、サーバ側ではそのURLにリダイレクトさせる処理だけ書けばよいことになります。
また、check_url()メソッドのdelayed_returnパラメータが何を意味するのか理解しやすいような記述にしておきました。trueならばcheckid_setupを意味し、falseならばcheckid_immediateモードを実行します。
認証結果の処理
OpenID::ConsumerApp::Controller::Login::Handlerモジュールを見てください。前と同様index()メソッドを見ます。
if (my $setup_url = $csr->user_setup_url) {
$c->res->redirect($setup_url);
}
elsif (my $vident = $csr->verified_identity) {
$c->res->body("Verified URL : " . $vident->url);
}
elsif ($csr->user_cancel) {
$c->res->body('Cancel');
}
else {
Catalyst::Exception->throw('Error : ' . $csr->err);
}
上記はindex()メソッドの一部だけ抜粋しました。IdPからリダイレクトされるケースと、そのタイミングで行うべき処理がここに凝縮されています。
まず、checkid_immediateモードでopenid.user_setup_urlがIdPから返されるケースでは、再びUser-Agentをその指定URLにリダイレクトさせなければなりません。このURLでEnd UserはIdPからConsumerへ、自分の認証結果をどのように伝えるかに関して聞かれるでしょう。
verified_identity()メソッドの実行が正常に終了した場合、Net::OpenID::VerifiedIdentityオブジェクトが返されます。このverified_identity()メソッドでdumbモードだった場合は、checkid_authenticationモードも実行してくれます。
最後のuser_cancelは、check系のモードの場合はid_resというモードでIdPからレスポンスが返ってきますが、例外としてはcheckid_setupモードを実行した場合に、End Userが認証結果の通知をキャンセルした場合、cancelというモードが返ってきます。従って、このcancelモードでのレスポンスがあった場合、user_cancel()メソッドはtrueとなります。
Profile
山口 徹(やまぐち とおる)
サイボウズ・ラボ株式会社のプログラマー。
バーテンダーからIT業界に転身後、様々なWeb制作を行い、大規模コミュニティサイトの開発・運用を経て、現在は研究開発の日々。Perl使い。
Perlを中心とした開発のノウハウやネタをShibuya Perl Mongersのイベント等で発表するなど講演活動も行う。
個人の開発日記は「Yet Another Hackadelic」、仕事のブログは「log4ZIGOROu」
Copyright © ITmedia, Inc. All Rights Reserved.