SAMLについて自由勝手に紹介

宿題をid:ZIGOROuさんから課せられたので、早めにやっつけで片付けます。でも入門、というのとはちょっとちがうだろうな。今回は、SAMLを知っている人には当たり前の話でも、知らない人はきっとわからないだろうことを補足するだけです。しかもとみたの主観的におもしろいと思ってるところだけ。

そもそも僕自身の能力的な話で、Libertyの時代も仕様は気になったところしか読んでないので、網羅的に書くのは正直つらいし、割に合わないと感じてます。ただ、今回はきっとtkudoさんが添削してくれるはずなので、かなりのびのびと書いちゃいます。

歴史のおさらい

まず間違え易い点として、SAML1.0とか1.1ってのは、SAMLが出たてのときの仕様なので、いまの話(v2.0)と結構違う。結構SAMLで検索するとこのころの話が引っかかったりする。むしろ今のSAML 2.0を調べようとしたらLiberty ID-FFの資料を見た方がまだいい。僕の認識ではLiberty ID-FF(の最終的なやつ、v1.2だっけ?)とSAML 2.0はそれほど差はないはず(と言い切れるほどよく仕様を見てないけど。マージされたShibbolethとか正直名前しか知らないし)


http://www.projectliberty.org/index.php/liberty/strategic_initiatives/federation

メッセージ

SAMLSOAPとかにのっけるXMLメッセージのスキーマの説明とかめんどい。そもそも良く知らない。SAMLを自前で実装したい人が見ればいい。ぜんぶLibertyかOASISのページかどっかにあったはず。だからここではメッセージのやり取りの仕方だけに注目する。

SAMLでのSSOの際のメッセージの流れは大きく分けて2つあって(ほんとはもっとあるみたいだけど書いてる本人が良く知らないので端折る)Browser/Artifact (HTTP Artifact)というやり方とBrowser/Post (HTTP Post)がある。ちなみにSAMLではこの「メッセージの流し方」のことをBindingと呼んでいたりする。

むちゃくちゃ短く言うと、SSOって結局、認証をする人(IdP)が認証を要求している人(SP)に対して現在アクセスしている人(User Agent)の識別子(Identifier)を渡さなきゃいけないんだけど、ただ単に渡すだけだったらなんでもありになっちゃうんで、それがちゃんと正しく渡されるか、というのが重要になる。で、SAMLにおいてこれを保証するやり方が上記の2つ。

Browser/Artifactというのは、一度IdP側で識別子を記したメッセージをArtifactという短めの文字列(トークン)に紐づけておいて、ブラウザリダイレクトの間にそのArtifactをSP側に渡してあげる。そしてSPからIdPへArtifactを利用してサーバ間で問い合わせることであらためてメッセージを取得する。まあつまりメッセージを参照渡しにしていると思えばいい。


SAML 2.0 - Wikipedia

Browser/Postというのは、識別子を記したメッセージを電子署名して、それをWebブラウザからform postを使ってSPに送りつけるというもの。SPは署名を検証した上でメッセージを読み取るので、識別子を正しく認識できる。Artifactの参照渡しに対して、メッセージをそのまま(ブラウザ経由で)送信するので値渡しといえるかな。署名を使うので、IdPとSPで事前に証明書を交換してあるというのが前提になる。


SAML 2.0 - Wikipedia


ここで疑問なのは、なんでこの2つがあるのか?ということ。ぶっちゃけBrowser/Artifactだけでもいいじゃないか?

Browser/Postがある理由は何か?明確にどこかに書いてあったわけじゃないけど(あるいはどこかに書いてあったかもしれないけどどこか忘れた)、IdPがイントラネットでもいいってことじゃないかな。つまりSPからIdPへの問い合わせが必須だと、IdPはSPから見て必ずネットワーク的に届く場所にいなければいけない。具体的に言うと、Browser/Postをつかえば、ASP(SaaS)でアプリケーションを提供しているWebサービスに対して、ActiveDirectory とか Sun Identity Manager とかで構築してあるイントラネットの基盤からログインできる可能性があるということ。普通の企業に対してDMZにサーバ置かせるのって、きついものね。Google AppsなんかはまさにそれをねらってSAMLってるんだと思うし。


SAML 2.0ではちょっとこのへん(Web SSO Profile ?)のあたりがちょっと変わってるみたいなんだけど、追いきれてないというのが実情。すいません。

プライバシー

これ重要。

イメージしてほしい。携帯のサブスクライバ番号とかFeliCaのIDが様々な事業者に共通に使われてるのって、ちょっと怖くない?ともすれば、どこかの店での購買履歴と、それとは全く異なる店で登録した会員情報のプロファイルが知らぬうちにいっしょに扱われてしまう可能性がある。各サイトに共通の識別子を使ってSSOするのは、それとまあ言ってみれば同じ問題を孕んでいる。

こういったいわゆる「名寄せ」の危険は、もちろん運用(当事者間の契約や法制度など)で回避してもいいのだけど、そもそも技術的にそれが回避できるのならばしてしまうほうがいい。

そのために、SAMLでは各SP<=>IdPのペアごとに異なる中間の識別子を使っている。IdPの持っているユーザ識別子(たとえば僕ならdel.icio.usのstomitaといったログインユーザ名)をそのままSPに渡したりする事はない。そのため、たとえ事業者の保管するユーザの情報が外に漏れたとしても、名寄せできる可能性は限られる。


http://sdc.sun.co.jp/javasystem/techtopics/identity/200705.html

ただ、そもそもこんなの必要ないよ、って言う立場の人がいるのも事実。IdPとSPの両方でいちいちマッピングを持つのは結構なオーバーヘッドだ。ただし、こういうプライバシーの要件が必須である分野(e.g. 政府)および地域(e.g. 欧州)があるということは頭に入れておいても損はないとおもう。

Identity Provider Discovery

この機能の名前はこれでいいんだっけ?実は自分的にはこれがSAMLの萌えのうちの一つだったりするけど。

SAMLではSPに対してIdPを複数持てる。そして使うIdPはユーザによって切り替えられる。ここまではまあOpenIDでもあたりまえ。ただし、SAMLでは一度IdPを決めたらおなじCircle内で共通にそれを覚えておいてくれるというすばらしい仕様がある。OpenIDがいちいちURL入れないといけなかったりするのとは大違い(ちょっと誇張)。

なんでこんなことができるのか?それを可能にするのが、Identity Provider Discovery ProfileというSAML内の仕様になる。

なにやってるかというと、同じCircleの中で共通のヴァーチャルなドメインを用意してその中の一つを自分のサーバにマッピングし、そこに一度リダイレクトしてDomain Cookieの値を読み書きする。Cookieにはそのユーザが使用するIdPの名前が書いてある。これで中央レジストリの必要なくユーザのIdPを決定できるという仕掛け。Common Domain CookieにはIdPの名前以外の情報は書かないから情報が漏れるといったこともない。

あれ、説明わかりにくい?まあとりあえず結構な協調を要求するhackだとおもう。

これって、とりあえず仕様としてはあるけど、実際どれだけ使われてるのかしらない。共通ドメインを用意するのって結構めんどくさかったりしないかな?という予想が、もしかしたら要らない懸念かもしれないが、とりあえずある。実際にここで使ってる、というのがあったら教えていただきたい。


以上、かなり偏ってお届けしたSAML紹介でした。ちゃんと学びたい人はtkudoさんの記事を読んでね!