今回は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/にアクセスすることで認証フォームが表示されます。
次に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モジュールを実際に使う部分となります。この処理の中で必要になる処理をもう一度おさらいしましょう。
実はこの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となります。
山口 徹(やまぐち とおる)
サイボウズ・ラボ株式会社のプログラマー。
バーテンダーからIT業界に転身後、様々なWeb制作を行い、大規模コミュニティサイトの開発・運用を経て、現在は研究開発の日々。Perl使い。
Perlを中心とした開発のノウハウやネタをShibuya Perl Mongersのイベント等で発表するなど講演活動も行う。
個人の開発日記は「Yet Another Hackadelic」、仕事のブログは「log4ZIGOROu」
Copyright © ITmedia, Inc. All Rights Reserved.