前回のおさらい
前回はRPのサンプルをRails上で動作させました。
この時に使用したRailsのアクションをまとめておきます。
-
ConsumerController#begin
- OpenIDリクエストを生成するRailsのアクション。
-
ConsumerController#complete
- OpenIDレスポンスを受信するRailsのアクション。
OpenIDの一番の特徴は、分散型である(複数のOPが存在する)ことです。
そのためDiscoveryなどの、OpenID特有の処理があります。
ですので今回は、OpenIDプロトコルの特徴的な箇所を、もう少し深く見ていきましょう。
取り上げるのはDiscoveryとSREGの2つです。
- Discovery
- 利用者が入力したOpenIDアカウント名(User-Supplied Identifier)を元にOPのログイン画面(OP Endpoint URL)を見つける。
- SREG
- OpenIDの拡張領域を使って利用者のメールアドレスなどをOPとRPで交換する。
Discovery…OpenIDアカウント名からOPのログイン画面を見つける
前回のサンプルでは、はじめに利用者がRPのログイン画面にOpenIDのアカウント名を入力しました。
このときOpenIDライブラリを使って、アカウント名からOpenIDリクエストを作成しています。
consumerはOpenID::Consumerクラスのオブジェクトで、oidreqはOpenID::Requestクラスのオブジェクトでした。
OpenID::Consumerオブジェクトのbeginメソッドを呼び出してOpenID::Requestオブジェクトを取得します。
OpenID::Requestオブジェクトのredirect_urlメソッドで、OPのログイン画面のURLを取得できます。
ここで重要なのは、利用者が入力するOpenIDアカウント名のURLと、利用者をOPのログイン画面へと誘導するためのURLは異なることです。
OpenIDの仕様では、利用者を誘導先となるOPのURLのことを、OPのエンドポイントURL(OP Endpoint URL)と呼びます。
- はてな
- 利用者が入力したOpenIDアカウント名(User-Supplied Identifier)
- http://www.hatena.ne.jp/kmachu/
- OPのエンドポイントURL(OP Endpoint URL)
- http://www.hatena.ne.jp/openid/server
- Yahoo!
- 利用者が入力したOpenIDアカウント名(User-Supplied Identifier)
- yahoo.com
- OPのエンドポイントURL(OP Endpoint URL)
- https://open.login.yahooapis.com/openid/op/auth
OpenIDでは不特定多数のOPが存在するため、事前に「はてなの場合はこのURL, Yahoo!の場合はこのURL」などとOP のエンドポイントURLを覚えておくことはできません。
OPのエンドポイントURLを動的に見つける必要があります。
前回のサンプルでは、OpenID::Consumerのbeginメソッドを呼び出したときにOPのURLを見つける処理をOpenIDライブラリが実行しています。
これが「discovery」です。
discoveryにはいくつかの方法があり、どの方法が使えるかはOP次第です。
- HTMLの中にOPのエンドポイントURLを記述する
- YadisとXRDSを用いる
概念を説明するよりも、具体的な例を見た方が分かりやすいと思います。
discoveryコマンドを使って認証サーバを見つけよう
ruby-openidライブラリには、OpenIDのdiscoveryを試すことができるdiscoverスクリプトが付属しています。
discoverは以下の場所にあります。
まず、はてなのOpenIDアカウント名を入力してみましょう。
Claimed identifierが入力したOpenIDアカウント名です。
discoverコマンドはこのURLを元にdiscoveryを行い、OPのエンドポイントURLであるhttp://www.hatena.ne.jp/openid/serverを見つけています。
同時に、このOPが対応しているOpenIDのバージョンが1.1であることも認識しています。
Yahoo!でも試してみましょう。
Yahoo!の場合は利用者のOpenIDアカウント名ではなくyahoo.comとだけ入力すればよかったですね。
このyahoo.comのことをOP Identifierと言います。
はてなの例と同じように、OPのエンドポイントURLであるhttps://open.login.yahooapis.com/openid/op/authを取得できました。
さらに、OpenID 2.0に対応していることと、PAPEという拡張領域に対応していることも分かります。
拡張領域については後ほど説明します。
なお、2007年4月時点で、はてなではOpenID2.0に対応していないため、OP Identifierを入力
してもdiscoveryに失敗します。
HTMLからOPのURLを取得する
はてなもYahoo!もdiscoveryによってOPのエンドポイントURLを見つけることができました。
ですが、はてなとYahoo!では、具体的な見つける手法は異なります。
もう少し詳しく見てみましょう。
はてなの場合は、利用者が入力したURLに存在するHTMLの中に、OpenIDのサーバ名がそのまま書かれています。
curlコマンドを使ってHTMLを取得し、openidという文字が含まれる行だけを抜き出してみます。
HTML文書に含まれるlink要素として、openid.serveのURLがhttp://www.hatena.ne.jp/openid/serverであることが記述されています。
この記述方法は、OpenIDのバージョン1のフォーマットです。
そのため、discoveコマンドは、はてなの OPがOpenID 1.1対応と判定したのです。
なお、OpenIDのバージョン1.1では、HTMLに記述する方法がdiscoveryの唯一の方法です。
Yadis+XRDSからOPのURLを取得する
次にYahoo!で試してみましょう。
同じようにcurlコマンドを使ってHTMLを取得し、openidという文字が含まれる行を探してみます。
結果は空でした。HTMLの中にはOpenIDの記述が書かれていないようです。
実はYahoo!では、OPのエンドポイントURLはHTML文書とは別の場所に置かれたXRDSというXML文書に書かれています。
XRDS文書の場所は、HTTPレスポンスヘッダに含まれる「X-XRDS-Location」というパラメータで指定されます。
指定されたURLにアクセスするとXRDS文書が取得できます。
このXMLの中に、OPのエンドポイントURLが記述されています。
このように、Yahoo!ではOPのエンドポイントURLを取得するために2つのステップを踏みます。
- 利用者が入力したURLからXRDS文書のURLを取得する
- XRDS文書を取得し、XRDS文書中に書かれているOPのエンドポイントURLを取得する
ステップが一つ増えているので、ちょっと複雑に感じるかもしれませんが、HTML中にURLを書くのではなく別のXML とすることで、より柔軟な記述が可能となっています。
なお、URLからXRDS文書を見つける手順はOpenIDとは別のYadisという仕様で決められています。
discoveryのまとめ
動的にOPのエンドポイントURLを見つけるdiscoveryには、以下の方法がありました。
- HTML文書に書かれたOPのエンドポイントURL取得する
- Yadisプロトコルを使ってXRDS文書を探し、XRDS文書に書かれたOPのエンドポイントURLを取得する
YadisとXRDS文書については、以下のサイトの資料が参考になります。
- 参考サイト
- URL:
http://d.hatena.ne.jp/ZIGOROu/20080317/1205725544
OpenIDの拡張領域
OpenIDは拡張領域(Extension)を定義できるようになっています。
拡張領域を使うことで、OpenIDのアカウント名を渡すだけでなく他の情報のやり取りも可能になります。
以下のような拡張領域が定義されています。
PAPEはOPにおける利用者の認証レベルを表すものです。
RPがOPに対して、例えばパスワードと一緒にデジタル証明書を用いて利用者を認証することを要求することができます。
RPが重要なデータを扱うサービスの場合は、OPに対して強固な認証を要求するといった使い方が想定されています。
ただし、本当にRPが要求したレベルの認証をOPが行っているかどうかは、RPには分かりません。
OPが「デジタル証明書で利用者を認証しました」とウソをつきながら、実はパスワードで認証しているということもあり得ます。
そのため、PAPEは信頼できるOPに対して使うことになるでしょう。
SREGとAXは、どちらも利用者の名前やメールアドレスなどの属性情報をOPに対して要求するものです。
AXはより汎用的な属性情報を扱えるようになっています。
これらの拡張を使うことで、ユーザ登録時の情報の入力を省くことができるというメリットがあります。
今回は、SREGを用いて利用者の名前とメールアドレスを取得するサンプルを試してみます。
SREGを使って利用者の名前とメールアドレスを取得する
前回動かしたRailsのサンプルには、SREGを使うためのインタフェースが用意されています。
ですが、利用者の情報を他のサイトに伝えるということから、SREGに対応しているOPはそれほど多くありません。
discoverコマンドを使うことで、OPがSREGに対応しているかどうかを確認することができます。
Yahoo!やはてなはSREGに対応していないので、ここではmyopenid.comというSREGに対応したOPを使います。
discoverコマンドで確認すると、OpenID2.0とSREG1.0に対応していることが分かります。
筆者はあらかじめmyopenid.com にアカウントを作成し、ニックネームとメールアドレスも登録しておきました。
前回も利用したRailsのサンプルを起動して、OpenIDのアカウント名を入力する画面にて「Request registration data」というチェックボックスをオンにするとOpenIDの拡張領域にSREGのパラメータが設定されます。
コードを見てみましょう。SREGの要求パラメータはOpenID::SReg::Requestクラスを使って管理します。
OpenID::SREG::Requesのオブジェクトを作り、フィールドに要求する値を設定します。
そして、 OpenID::Requestクラスのオブジェクトに対して、add_extensionメソッドを呼び出してOpenID::SReg::Requestオブジェクトを登録します。
この例では、メールアドレスとニックネームを必須項目として要求しています。
OPであるmyopenid.comのログイン画面では、ログイン後にメールアドレスやニックネームをRPへと渡してよいかの確認が行われます。
ここでmyopenid.comが面白いのは、複数の登録データを「ペルソナ」として選択できるようになっていることです。
Yahoo!がRPに渡すIDを選べるようになっていたように、myopenid.comではRPに渡すメールアドレスやニックネームを選ぶことができます。
ログインが終わりOPからRPへと戻ってくると、OPに登録していたニックネームやメールアドレスがRPの画面に表示されています。
これによってRP でのユーザ登録時の情報を入力する手間を省くことができます。
ソースコードを見てみましょう。
まず、OpenIDのレスポンスを管理するOpenID::Responseオブジェクト(oidresp)からOpenID::SReg::Responseオブジェクトを生成します。
OPから送られてきたデータは、ハッシュ形式で取り出すことができます。
例えば、メールアドレスはsreg_resp.data['email']で取得できます。
SREでは、OPは利用者から預かった情報をRPへ渡すことになるので、慎重に利用する必要があるでしょう。
特に、RPやOPにおいてログイン画面などで利用者に対する周知をしっかり行わないと、「知らないうちに個人情報が漏れた!」と誤解されてしまうかもしれません。
そのためか、多数の利用者を抱えるOPにて、SREGを提供しているところはまだあまりありません。
しかし、SREGやAXは可能性を秘めている仕組みですので、面白い使い方が出てくることを期待したいです。
終わりに
今回はOpenIDの内部の仕組みとして、利用者が入力したOpenIDアカウント名(User-Supplied Identifier)からOPのエンドポイント(OP Endpoint URL)を見つけるdiscoveryや、拡張領域を使ってメールアドレスなどを交換するSREGについて説明しました。
内部の仕組みは複雑なところがありますが、これらの面倒な処理はOpenIDライブラリが担当してくれます。
次回はいよいよ、OpenIDを使ったサービスを作ってみることにしましょう。