先日の
OpenID Technight vol.8 @ 大阪でも触れましたが、時間もなかったので簡単にしか話が出来なかったので、振り返りつつ解説をしていきたいと思います。
■ACS の機能のおさらいAppFabric ACS v2 は Windows Azure 上にデプロイされたクラウド上の STS / Federation Provider です。主な機能は「外部 Identity Provider から発行されたセキュリティ・トークンの形式を変換して、要求元のアプリケーションへ渡す
ゲートウェイ機能」であり、対応するプロトコルとしては ws-federation、OpenID、OAuth2.0 などがあります。
ざっくりいうと Yahoo!やGoogle、facebookなどで発行されたセキュリティ・トークンを ws-federation に乗せた SAML トークンとして Windows Identity Foundation(WIF)を使った .NET アプリケーションへ渡す、という役割を持ちます。
このことによって各 .NET アプリケーションは Yahoo! や Google に対応する形で個別のコードを記述する必要がなくなり開発効率があがる、というのが最大の利点といえます。
■ACS の Facebook 連携とはACS の Facebook 連携は OAuth2.0 が利用されています。具体的に言うと、Facebook の認可サーバ(AuthZ Server)からアクセス・トークンを取得するのがここで言う連携の最大の目的であり実体です。
以下の図でいう OAuth AuthZ Server / OAuth Resource Server が Facebook に当たります。ACS は Facebook からアクセス・トークンを取得しています。
■混同しやすい点ここが最大の注意点なのですが、Yahoo! や Google、オンプレミスの AD FS2.0 との連携に使われる OpenID や ws-federation といったプロトコルと OAuth2.0 は若干性質が違います。
例えば ACS の Google 連携 では(おそらく)OpenID Authentication を利用しているのであくまで認証の外部化を目的としていますし、AD FS2.0 との連携では ws-federation を利用しているので認証およびクレームの伝搬を目的としています。
しかし、Facebook 連携に使用している OAuth2.0 は基本的には「保護されたリソースへアクセスするための認可を受けること」を目的としています。つまり、認証自体を目的としている訳でも、Facebook 上の属性をクレームとして伝搬することを目的としている訳でもありません。
ただ、結果として ACS を経由することで .NET アプリケーションは個別に認証機能を実装する必要はなくなりますし、ある程度のクレーム情報については取得することが出来てしまいますので、認証を受けて名前やメールアドレスを取得する、という目的での利用をすることも可能ではある訳です。
Facebook から取得したクレーム
■Facebook 連携の使い方では、本来(?)のACS / Facebook 連携の使い方、というより OAuth の使い方はどのような物なのでしょうか?
先ほどの Facebook から取得したクレームの中に claimType が http://www.facebook.com/claims/AccessToken となっている物がありました。これが ACS が Facebook から取得したアクセス・トークンです。
本来は Facebook の保持するリソースに対して API アクセスを行うために Facebook の認可サーバがクライアント(RESTful Web Service)に対して払い出すのがこのアクセス・トークンであり、ACS の Facebook 連携においては ACS が Facebook から見てクライアントとなります。
しかし、一番最初に書いた通り、ACS は「ゲートウェイ」なので、Facebook から取得したアクセス・トークンを SAML トークンの1つの Assertion として変換し、ws-federation プロトコルに乗せて WIF を使った .NET アプリケーションへ渡します。
それが、先にも出したこの図の左半分です。
後は、 .NET アプリケーションが受け取ったアクセス・トークンを使って Facebook の API へアクセスしリソースの取得や各種操作を行う、というのが本来の Facebook 連携を行う意味合いに沿った使い方、ということになります。
例えば、Facebook から誕生日情報を取得したければ、例えば以下の様なコードを書くことになります。
var f_birthday = new WebClient().DownloadString(@"https://graph.facebook.com/me?fields=birthday&access_token=" + [ACS より取得したアクセス・トークン]); var json = DynamicJson.Parse(f_birthday); TextBox1.Text = json.birthday; |
内容ですが、Facebook の graph API (http://graph.facebook.com)に対して自分の誕生日(me?fields=birthday)を取得したアクセス・トークンをパラメータとして付与(access_token=[ACS より取得したアクセス・トークン])して HTTP/GET する、というものです。
結果、json 形式で誕生日の文字列が返却されますので、例では Dynamic JSON(http://dynamicjson.codeplex.com/)を使って文字列をパースしてテキストボックスに表示をさせています。
同様に Facebook のウォールへの投稿の例です。
System.Collections.Specialized.NameValueCollection ps = new System.Collections.Specialized.NameValueCollection(); ps.Add("access_token", [ACS から取得したアクセス・トークン]); ps.Add("message", [投稿したいメッセージ]); WebClient wc = new WebClient(); byte[] resData = wc.UploadValues(@"https://graph.facebook.com/me/feed", ps); wc.Dispose(); |
今度は HTTP/POST メソッドを利用した例ですが、考え方は同じで ACS から取得したアクセス・トークンおよび投稿したいメッセージを graph API の me/feed に与える、というやり方です。
■アクセス・トークンの扱いについてここまで ACS の Facebook 連携の使い方について整理をしてきましたが、1点注意をすべき点としてアクセス・トークンの取り扱いがあります。
これは OAuth を使ったアプリケーション全般に言えますが、取得したアクセス・トークンはあくまで文字列なので他のアプリケーションから再利用することが出来てしまいます。その意味でアクセス・トークンは Facebook のリソースへアクセスするための「合鍵」と言うことが出来ます。
例えば、取得したアクセス・トークンをコピーして全く別のアプリケーションから Facebook のリソースへアクセスすることも出来てしまいます。
フォームアプリケーションに取得したアクセス・トークンをコピーして Facebook のリソースへアクセスする例
このようなことを防ぐためにもアプリケーション開発者は取得したアクセス・トークンが外部に漏れないように保護することが必要です。
また、これも当然ですが ACS に設定する Facebook へのアクセス許可の範囲については必要最低限に絞っておくことが肝要です。